mirror of https://github.com/voidlizard/hbs2
git-hbs2-http - very basic git http dumb algorithm
for fetching repos from hbs2-git for third-side programs (like nix). pushes are not supported (yet?).
This commit is contained in:
parent
55cdf976da
commit
0af3056664
|
@ -0,0 +1,27 @@
|
||||||
|
FIXME: hbs2-git-config-path-ux
|
||||||
|
1. Пользователю неочевидно, где этот конфиг искать ( ~/.local/config/hbs2-git/repo/config )
|
||||||
|
2. Если пользователь переименует репозиторий, то путь к конфигу станет неактуален
|
||||||
|
и это вызовет непонятную внезапную проблему.
|
||||||
|
|
||||||
|
Решение:
|
||||||
|
Пока непонятно. Если привязаться к inode, то при перемещении между FS будет ломаться,
|
||||||
|
и кроссплатформенность пострадает.
|
||||||
|
|
||||||
|
Кажется, при инициализации репо надо заводить cookie, и сохранять её в конфиге гита (буэ).
|
||||||
|
Тогда все операции ведутся через эту cookie, все развязки в стейте через эту cookie,
|
||||||
|
тогда importRefLogNew начинает работать с многими каталогами git, стейт с одной
|
||||||
|
стороны глобальный, с другой стороны зависит от cookie.
|
||||||
|
|
||||||
|
Если пользователь специально или случайно удалит/поменяет cookie -- то импорт для этого
|
||||||
|
репозитория пойдёт заново (ну и что, мы этого и хотели. глобальный у нас
|
||||||
|
только logobject и связаные с ним вью и таблицы, а таблицы, которые отмечают
|
||||||
|
обработанные данные --- имеют локальный смысл. )
|
||||||
|
|
||||||
|
Кроме того, надо задуматься о перемещении конфига в каталог гит локально,
|
||||||
|
что бы избежать проблем 1 и 2.
|
||||||
|
|
||||||
|
Введение конфига, привязанного к cookie, еще больше усугубит проблему (1), но решит
|
||||||
|
в принципе проблему 2.
|
||||||
|
|
||||||
|
От конфига нам, кстати, вообще ничего не нужно, кроме указания ключа записи в рефлог.
|
||||||
|
Кажется, можно его просто упразднить или писать в тот же gitconfig.
|
|
@ -0,0 +1,249 @@
|
||||||
|
module Main where
|
||||||
|
|
||||||
|
import HBS2.Prelude.Plated
|
||||||
|
import HBS2.Clock
|
||||||
|
|
||||||
|
import HBS2Git.App
|
||||||
|
import HBS2Git.State
|
||||||
|
import HBS2Git.Import (getLogFlags, importRefLogNew)
|
||||||
|
import HBS2Git.GitRepoLog
|
||||||
|
import HBS2.Git.Types
|
||||||
|
import HBS2.Data.Types.Refs
|
||||||
|
import HBS2.Data.Detect (deepScan,ScanLevel(..))
|
||||||
|
import HBS2.OrDie
|
||||||
|
|
||||||
|
import HBS2.System.Logger.Simple
|
||||||
|
|
||||||
|
import Codec.Compression.Zlib (compress)
|
||||||
|
import Control.Concurrent
|
||||||
|
import Control.Exception
|
||||||
|
import Control.Monad
|
||||||
|
import Control.Monad.Trans.Maybe
|
||||||
|
import Control.Monad.Trans.Resource
|
||||||
|
import Data.ByteString.Lazy.Char8 qualified as LBS
|
||||||
|
import Data.Function
|
||||||
|
import Data.Functor
|
||||||
|
import Data.HashMap.Strict as HashMap
|
||||||
|
import Data.List (sortOn)
|
||||||
|
import Data.Text.Lazy qualified as Text
|
||||||
|
import Lens.Micro.Platform
|
||||||
|
import Network.HTTP.Types.Status
|
||||||
|
import Network.Wai.Handler.Warp (Port)
|
||||||
|
import Network.Wai.Middleware.RequestLogger
|
||||||
|
import System.Directory
|
||||||
|
import System.FilePath.Posix
|
||||||
|
import System.IO.Temp
|
||||||
|
import System.Timeout (timeout)
|
||||||
|
import Text.InterpolatedString.Perl6 (qc)
|
||||||
|
import UnliftIO.Async
|
||||||
|
|
||||||
|
import Streaming.ByteString qualified as SB
|
||||||
|
import Streaming.Zip qualified as SZip
|
||||||
|
|
||||||
|
import Web.Scotty
|
||||||
|
|
||||||
|
instance Parsable RepoRef where
|
||||||
|
parseParam txt = fromStringMay @RepoRef (Text.unpack txt)
|
||||||
|
& maybe (Left [qc|{txt}|]) Right
|
||||||
|
|
||||||
|
instance Parsable GitRef where
|
||||||
|
parseParam txt = Right $ fromString (Text.unpack txt)
|
||||||
|
|
||||||
|
getAppStatePath :: MonadIO m => RepoRef -> m FilePath
|
||||||
|
getAppStatePath repo = do
|
||||||
|
stateDir <- getAppStateDir
|
||||||
|
pure $ stateDir </> show (pretty repo)
|
||||||
|
|
||||||
|
|
||||||
|
blockSource :: MonadIO m => API -> HashRef -> SB.ByteStream m ()
|
||||||
|
blockSource api h = do
|
||||||
|
deepScan ScanDeep (const none) (fromHashRef h) (readBlockFrom api . HashRef) $ \ha -> do
|
||||||
|
sec <- lift $ readBlockFrom api (HashRef ha) `orDie` [qc|missed block {pretty ha}|]
|
||||||
|
when (h /= HashRef ha) do
|
||||||
|
SB.fromLazy sec
|
||||||
|
|
||||||
|
unpackObjects :: MonadIO m => API -> HashRef -> FilePath -> m ()
|
||||||
|
unpackObjects catApi lo path = do
|
||||||
|
|
||||||
|
let logPath = path </> show (pretty lo)
|
||||||
|
let logFile = logPath </> "data"
|
||||||
|
|
||||||
|
liftIO $ createDirectoryIfMissing True logPath
|
||||||
|
|
||||||
|
flags <- getLogFlags (readBlockFrom catApi) lo
|
||||||
|
let gzipped = or $ False : [ True | "gz" <- universeBi flags ]
|
||||||
|
let unzipped = if gzipped then SZip.gunzip else id
|
||||||
|
debug $ "GOT FLAGS:" <+> pretty lo <+> pretty flags
|
||||||
|
|
||||||
|
liftIO $ do
|
||||||
|
runResourceT $ SB.writeFile logFile $ unzipped $ blockSource catApi lo
|
||||||
|
|
||||||
|
gitRepoLogScan True logFile $ \entry mlbs -> do
|
||||||
|
|
||||||
|
let tp = case view gitLogEntryType entry of
|
||||||
|
GitLogEntryCommit -> Just Commit
|
||||||
|
GitLogEntryTree -> Just Tree
|
||||||
|
GitLogEntryBlob -> Just Blob
|
||||||
|
_ -> Nothing
|
||||||
|
|
||||||
|
|
||||||
|
let r = (,,) <$> tp
|
||||||
|
<*> view gitLogEntryHash entry
|
||||||
|
<*> mlbs
|
||||||
|
|
||||||
|
maybe1 r none $ \(t, eh, lbs) -> do
|
||||||
|
let fname = logPath </> show (pretty eh)
|
||||||
|
let pref = fromString (show (pretty t) <> " " <> show (LBS.length lbs) <> "\0")
|
||||||
|
-- debug $ "writing object" <+> pretty eh <+> pretty (LBS.unpack $ LBS.takeWhile (/= '\0') pref)
|
||||||
|
let co = compress (pref <> lbs)
|
||||||
|
liftIO $ LBS.writeFile fname co
|
||||||
|
|
||||||
|
retryFor :: RealFrac r => Int -> r -> Timeout 'Seconds -> IO a -> IO (Maybe a)
|
||||||
|
retryFor num waity sleep action = timeout (ceiling $ waity * 1000000) $ go num
|
||||||
|
where
|
||||||
|
go 0 = action
|
||||||
|
go n = ( (Just <$> action) `catch` handler ) >>= maybe (go (n-1)) pure
|
||||||
|
handler (_ :: SomeException) = pause @'Seconds sleep >> pure Nothing
|
||||||
|
|
||||||
|
dumbHttpServe :: MonadUnliftIO m => Port -> m ()
|
||||||
|
dumbHttpServe pnum = do
|
||||||
|
|
||||||
|
locks <- liftIO $ newMVar (HashMap.empty @HashRef @(MVar ()))
|
||||||
|
|
||||||
|
catApi <- liftIO (retryFor 100 30 0.5 detectHBS2PeerCatAPI) `orDie` [qc|Can't locate hbs2-peer API|]
|
||||||
|
|
||||||
|
notice $ "hbs2-peer API:" <+> pretty catApi
|
||||||
|
|
||||||
|
-- TODO: lru-like-cache-for-unpacked-logs
|
||||||
|
-- Деражть кэш, обновлять в нём таймстемпы
|
||||||
|
-- доступа к логам.
|
||||||
|
-- как только запись протухла - сносить каталог
|
||||||
|
-- с логом, тогда в следующий раз будет обратно
|
||||||
|
-- распакован
|
||||||
|
|
||||||
|
updater <- async $ forever do
|
||||||
|
pause @'Seconds 300
|
||||||
|
pure ()
|
||||||
|
|
||||||
|
runResourceT do
|
||||||
|
|
||||||
|
let myTempDir = "hbs-git-http"
|
||||||
|
temp <- liftIO getCanonicalTemporaryDirectory
|
||||||
|
|
||||||
|
(_,dir) <- allocate (createTempDirectory temp myTempDir) removeDirectoryRecursive
|
||||||
|
|
||||||
|
|
||||||
|
liftIO $ scotty pnum $ do
|
||||||
|
|
||||||
|
middleware logStdoutDev
|
||||||
|
|
||||||
|
get "/:repo/info/refs" $ do
|
||||||
|
repo <- param @RepoRef "repo"
|
||||||
|
res <- liftIO do
|
||||||
|
db <- makeDbPath repo >>= dbEnvReadOnly
|
||||||
|
refs <- withDB db stateGetActualRefs
|
||||||
|
let answ = Text.unlines $ Text.pack <$> [ show (pretty h) <> "\t" <> show (pretty r) | (r,h) <- refs ]
|
||||||
|
shutdownDB db
|
||||||
|
pure answ
|
||||||
|
|
||||||
|
text res
|
||||||
|
|
||||||
|
-- | REPO OBJECT REF
|
||||||
|
get (regex "^/(.+)/(refs/.+)$") $ do
|
||||||
|
repo <- fromString <$> param "1" -- reflog
|
||||||
|
ref <- param "2" -- refname
|
||||||
|
val <- liftIO do
|
||||||
|
db <- makeDbPath repo >>= dbEnvReadOnly
|
||||||
|
debug $ "QUERY: " <+> pretty ref
|
||||||
|
val <- withDB db $ stateGetActualRefValue ref
|
||||||
|
shutdownDB db
|
||||||
|
pure val
|
||||||
|
|
||||||
|
maybe1 val (status status404) $ \x -> do
|
||||||
|
text $ Text.pack $ show $ pretty x
|
||||||
|
|
||||||
|
get "/:repo/objects/:dd/:rest" $ do
|
||||||
|
repo <- param @RepoRef "repo"
|
||||||
|
dd <- param @String "dd"
|
||||||
|
rest <- param @String "rest"
|
||||||
|
let ha = fromString ( dd <> rest )
|
||||||
|
|
||||||
|
res <- runMaybeT do
|
||||||
|
db <- liftIO $ makeDbPath repo >>= dbEnvReadOnly
|
||||||
|
lo <- MaybeT $ liftIO $ withDB db $ stateGetGitLogObject ha
|
||||||
|
shutdownDB db
|
||||||
|
|
||||||
|
let logDir = dir </> show (pretty lo)
|
||||||
|
let fname = logDir </> show (pretty ha)
|
||||||
|
|
||||||
|
here <- liftIO $ doesFileExist fname
|
||||||
|
|
||||||
|
if here then do
|
||||||
|
pure fname
|
||||||
|
else do
|
||||||
|
lock <- liftIO $ getLock locks lo
|
||||||
|
MaybeT $ liftIO $ withMVar lock $ \_ -> do
|
||||||
|
unpackObjects catApi lo dir
|
||||||
|
here1 <- liftIO $ doesFileExist fname
|
||||||
|
if here1 then do
|
||||||
|
pure (Just fname)
|
||||||
|
else do
|
||||||
|
pure Nothing
|
||||||
|
|
||||||
|
maybe1 res (status status404) $ \r -> do
|
||||||
|
addHeader "content-type" "application/octet-stream"
|
||||||
|
file r
|
||||||
|
|
||||||
|
get "/:topic/HEAD" $ do
|
||||||
|
repo <- fromString <$> param "topic"
|
||||||
|
headRef <- liftIO $ do
|
||||||
|
db <- liftIO $ makeDbPath repo >>= dbEnvReadOnly
|
||||||
|
re <- withDB db stateGetActualRefs <&> headMay . sortOn guessHead . fmap (view _1)
|
||||||
|
shutdownDB db
|
||||||
|
pure re
|
||||||
|
|
||||||
|
case headRef of
|
||||||
|
Nothing -> status status404
|
||||||
|
Just hd -> do
|
||||||
|
text [qc|ref: {show $ pretty $ hd}|]
|
||||||
|
|
||||||
|
cancel updater
|
||||||
|
|
||||||
|
where
|
||||||
|
getLock locks k = modifyMVar locks $ \m -> do
|
||||||
|
case HashMap.lookup k m of
|
||||||
|
Just lock -> return (m, lock)
|
||||||
|
Nothing -> do
|
||||||
|
lock <- newMVar ()
|
||||||
|
pure (HashMap.insert k lock m, lock)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
-- TODO: hbs2-peer-http-api-reflog-fetch
|
||||||
|
-- Ручка, что бы сделать reflog fetch
|
||||||
|
|
||||||
|
-- TODO: hbs2-peer-dyn-reflog-subscribe
|
||||||
|
-- Возможность динамически подписываться на рефлоги
|
||||||
|
|
||||||
|
-- TODO: hbs2-peer-hook-on-reflog-update
|
||||||
|
-- нужен хук, который даст возможность обрабатывать апдейты
|
||||||
|
-- по нужному рефлогу. нужно много где
|
||||||
|
|
||||||
|
|
||||||
|
main :: IO ()
|
||||||
|
main = do
|
||||||
|
|
||||||
|
setLogging @DEBUG debugPrefix
|
||||||
|
setLogging @INFO defLog
|
||||||
|
setLogging @ERROR errorPrefix
|
||||||
|
setLogging @WARN warnPrefix
|
||||||
|
setLogging @NOTICE noticePrefix
|
||||||
|
setLoggingOff @TRACE
|
||||||
|
|
||||||
|
-- TODO: hbs2-git-own-config
|
||||||
|
|
||||||
|
-- FIXME: port-number-to-config
|
||||||
|
dumbHttpServe 4017
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -72,11 +72,6 @@ capabilities :: BS.ByteString
|
||||||
capabilities = BS.unlines ["push","fetch"]
|
capabilities = BS.unlines ["push","fetch"]
|
||||||
|
|
||||||
|
|
||||||
guessHead :: GitRef -> Integer
|
|
||||||
guessHead = \case
|
|
||||||
"refs/heads/master" -> 0
|
|
||||||
"refs/heads/main" -> 0
|
|
||||||
_ -> 1
|
|
||||||
|
|
||||||
loop :: forall m . ( MonadIO m
|
loop :: forall m . ( MonadIO m
|
||||||
, MonadCatch m
|
, MonadCatch m
|
||||||
|
|
|
@ -8,12 +8,13 @@ import HBS2Git.State
|
||||||
import HBS2Git.Config
|
import HBS2Git.Config
|
||||||
import HBS2Git.ListRefs
|
import HBS2Git.ListRefs
|
||||||
|
|
||||||
|
import Control.Monad.Catch (MonadMask)
|
||||||
import Data.Foldable
|
import Data.Foldable
|
||||||
import Prettyprinter.Render.Terminal
|
import Prettyprinter.Render.Terminal
|
||||||
|
|
||||||
data ShowObject = ShowRef RepoRef | ShowConfig
|
data ShowObject = ShowRef RepoRef | ShowConfig
|
||||||
|
|
||||||
showRef :: MonadIO m => RepoRef -> App m ()
|
showRef :: (MonadIO m, MonadMask m) => RepoRef -> App m ()
|
||||||
showRef h = do
|
showRef h = do
|
||||||
db <- makeDbPath h >>= dbEnv
|
db <- makeDbPath h >>= dbEnv
|
||||||
-- FIXME: re-implement-showRef
|
-- FIXME: re-implement-showRef
|
||||||
|
@ -27,25 +28,25 @@ showRef h = do
|
||||||
-- print $ pretty "last operations:"
|
-- print $ pretty "last operations:"
|
||||||
-- for_ imported (\(t,h1,h2) -> print $ pretty t <+> pretty h1 <+> pretty h2)
|
-- for_ imported (\(t,h1,h2) -> print $ pretty t <+> pretty h1 <+> pretty h2)
|
||||||
|
|
||||||
showRefs :: MonadIO m => App m ()
|
showRefs :: (MonadIO m, MonadMask m) => App m ()
|
||||||
showRefs = do
|
showRefs = do
|
||||||
liftIO $ putDoc $ line <> green "References:" <> section
|
liftIO $ putDoc $ line <> green "References:" <> section
|
||||||
runListRefs
|
runListRefs
|
||||||
|
|
||||||
showConfig :: MonadIO m => App m ()
|
showConfig :: (MonadIO m, MonadMask m) => App m ()
|
||||||
showConfig = liftIO do
|
showConfig = liftIO do
|
||||||
ConfigPathInfo{..} <- getConfigPathInfo
|
ConfigPathInfo{..} <- getConfigPathInfo
|
||||||
cfg <- readFile configFilePath
|
cfg <- readFile configFilePath
|
||||||
putDoc $ green "Config file location:" <> section <> pretty configFilePath <> section
|
putDoc $ green "Config file location:" <> section <> pretty configFilePath <> section
|
||||||
putDoc $ green "Config contents:" <> line <> pretty cfg
|
putDoc $ green "Config contents:" <> line <> pretty cfg
|
||||||
|
|
||||||
showSummary :: MonadIO m => App m ()
|
showSummary :: (MonadIO m, MonadMask m) => App m ()
|
||||||
showSummary = do
|
showSummary = do
|
||||||
showRefs
|
showRefs
|
||||||
liftIO $ putDoc section
|
liftIO $ putDoc section
|
||||||
showConfig
|
showConfig
|
||||||
|
|
||||||
runShow :: MonadIO m => Maybe ShowObject -> App m ()
|
runShow :: (MonadIO m, MonadMask m) => Maybe ShowObject -> App m ()
|
||||||
runShow (Just (ShowRef h)) = showRef h
|
runShow (Just (ShowRef h)) = showRef h
|
||||||
runShow (Just ShowConfig) = showConfig
|
runShow (Just ShowConfig) = showConfig
|
||||||
runShow Nothing = showSummary
|
runShow Nothing = showSummary
|
||||||
|
|
|
@ -173,3 +173,28 @@ executable git-remote-hbs2
|
||||||
hs-source-dirs: git-hbs2
|
hs-source-dirs: git-hbs2
|
||||||
default-language: Haskell2010
|
default-language: Haskell2010
|
||||||
|
|
||||||
|
executable git-hbs2-http
|
||||||
|
import: shared-properties
|
||||||
|
main-is: GitHttpDumbMain.hs
|
||||||
|
|
||||||
|
ghc-options:
|
||||||
|
-threaded
|
||||||
|
-rtsopts
|
||||||
|
"-with-rtsopts=-N4 -A64m -AL256m -I0"
|
||||||
|
|
||||||
|
other-modules:
|
||||||
|
|
||||||
|
-- other-extensions:
|
||||||
|
build-depends:
|
||||||
|
base, hbs2-git
|
||||||
|
, http-types
|
||||||
|
, optparse-applicative
|
||||||
|
, scotty
|
||||||
|
, wai-extra
|
||||||
|
, warp
|
||||||
|
, zlib
|
||||||
|
|
||||||
|
hs-source-dirs: git-hbs2-http
|
||||||
|
default-language: Haskell2010
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -116,6 +116,11 @@ normalizeRef (GitRef x) = GitRef "refs/heads/" <> GitRef (fromMaybe x (Text.stri
|
||||||
where
|
where
|
||||||
strip = Text.dropWhile (=='+')
|
strip = Text.dropWhile (=='+')
|
||||||
|
|
||||||
|
guessHead :: GitRef -> Integer
|
||||||
|
guessHead = \case
|
||||||
|
"refs/heads/master" -> 0
|
||||||
|
"refs/heads/main" -> 0
|
||||||
|
_ -> 1
|
||||||
|
|
||||||
shutUp :: MonadIO m => m ()
|
shutUp :: MonadIO m => m ()
|
||||||
shutUp = do
|
shutUp = do
|
||||||
|
|
|
@ -241,7 +241,11 @@ writeBlockIO api bs = do
|
||||||
readBlock :: forall m . (HasCatAPI m, MonadIO m) => HashRef -> m (Maybe ByteString)
|
readBlock :: forall m . (HasCatAPI m, MonadIO m) => HashRef -> m (Maybe ByteString)
|
||||||
readBlock h = do
|
readBlock h = do
|
||||||
req1 <- getHttpCatAPI
|
req1 <- getHttpCatAPI
|
||||||
let reqs = req1 <> "/" <> show (pretty h)
|
readBlockFrom req1 h
|
||||||
|
|
||||||
|
readBlockFrom :: forall m . (MonadIO m) => API -> HashRef -> m (Maybe ByteString)
|
||||||
|
readBlockFrom api h = do
|
||||||
|
let reqs = api <> "/" <> show (pretty h)
|
||||||
req <- liftIO $ parseRequest reqs
|
req <- liftIO $ parseRequest reqs
|
||||||
resp <- httpLBS req
|
resp <- httpLBS req
|
||||||
|
|
||||||
|
|
|
@ -68,15 +68,15 @@ makeLenses 'ExportEnv
|
||||||
|
|
||||||
|
|
||||||
exportRefDeleted :: forall o m . ( MonadIO m
|
exportRefDeleted :: forall o m . ( MonadIO m
|
||||||
, MonadCatch m
|
, MonadCatch m
|
||||||
-- , MonadMask m
|
, MonadMask m
|
||||||
, MonadUnliftIO m
|
, MonadUnliftIO m
|
||||||
, HasCatAPI m
|
, HasCatAPI m
|
||||||
, HasConf m
|
, HasConf m
|
||||||
, HasRefCredentials m
|
, HasRefCredentials m
|
||||||
, HasProgress m
|
, HasProgress m
|
||||||
, ExportRepoOps o
|
, ExportRepoOps o
|
||||||
)
|
)
|
||||||
=> o
|
=> o
|
||||||
-> RepoRef
|
-> RepoRef
|
||||||
-> GitRef
|
-> GitRef
|
||||||
|
|
|
@ -72,14 +72,87 @@ blockSource h = do
|
||||||
|
|
||||||
liftIO $ readTVarIO tsize <&> fromIntegral
|
liftIO $ readTVarIO tsize <&> fromIntegral
|
||||||
|
|
||||||
|
getLogFlags :: MonadIO m
|
||||||
|
=> (HashRef -> m (Maybe LBS.ByteString))
|
||||||
|
-> HashRef
|
||||||
|
-> m (Maybe [Text])
|
||||||
|
|
||||||
|
getLogFlags doRead h = do
|
||||||
|
|
||||||
|
runMaybeT do
|
||||||
|
|
||||||
|
treeBs <- MaybeT $ doRead h
|
||||||
|
|
||||||
|
let something = tryDetect (fromHashRef h) treeBs
|
||||||
|
let meta = mconcat $ rights [ parseTop (Text.unpack s) | ShortMetadata s <- universeBi something ]
|
||||||
|
|
||||||
|
-- TODO: check-if-it-is-hbs2-git-log
|
||||||
|
let tp = lastMay [ "hbs2-git-push-log"
|
||||||
|
| (ListVal (Key "type:" [SymbolVal "hbs2-git-push-log"]) ) <- meta
|
||||||
|
]
|
||||||
|
|
||||||
|
guard ( tp == Just "hbs2-git-push-log" )
|
||||||
|
|
||||||
|
pure $ mconcat [ Text.splitOn ":" (Text.pack (show $ pretty s))
|
||||||
|
| (ListVal (Key "flags:" [SymbolVal s]) ) <- meta
|
||||||
|
]
|
||||||
|
|
||||||
|
class HasImportOpts a where
|
||||||
|
importForce :: a -> Bool
|
||||||
|
importDontWriteGit :: a -> Bool
|
||||||
|
|
||||||
|
instance HasImportOpts Bool where
|
||||||
|
importForce f = f
|
||||||
|
importDontWriteGit = const False
|
||||||
|
|
||||||
|
instance HasImportOpts (Bool, Bool) where
|
||||||
|
importForce = fst
|
||||||
|
importDontWriteGit = snd
|
||||||
|
|
||||||
|
-- FIXME: ASAP-will-work-only-for-one-repo
|
||||||
|
-- сейчас все транзакции помечаются, как обработанные
|
||||||
|
-- в глобальном стейте для ссылки. таким образом,
|
||||||
|
-- если мы вызвали для одного репозитория,
|
||||||
|
-- то import не будет работать для остальных, т.к. решит,
|
||||||
|
-- что всё обработано.
|
||||||
|
--
|
||||||
|
-- Решение:
|
||||||
|
-- Вариант N1. Держать стейт локально в каждом
|
||||||
|
-- каталоге git.
|
||||||
|
-- Минусы:
|
||||||
|
-- - большой оверхед по данным
|
||||||
|
-- - мусор в каталоге git
|
||||||
|
-- - например, git-hbs2-http вообще работает без "репозитория",
|
||||||
|
-- как ему быть
|
||||||
|
--
|
||||||
|
-- Вариант N2. сделать развязку через какой-то ID
|
||||||
|
-- репозитория или путь к нему.
|
||||||
|
-- Минусы:
|
||||||
|
-- - выглядит хрупко
|
||||||
|
-- - например, git-hbs2-http вообще работает без "репозитория",
|
||||||
|
-- как ему быть
|
||||||
|
--
|
||||||
|
-- Вариант N3. БД обновлять отдельно, объекты git - отдельно
|
||||||
|
-- для каждого репозитория, запоминать (где?) проигранные для
|
||||||
|
-- него логи.
|
||||||
|
-- Минусы:
|
||||||
|
-- - двойное сканирование файлов логов - получение, распаковка,
|
||||||
|
-- сканирование и т.п. сначала для БД, потом для непосредственно
|
||||||
|
-- репозитория
|
||||||
|
--
|
||||||
importRefLogNew :: ( MonadIO m
|
importRefLogNew :: ( MonadIO m
|
||||||
, MonadUnliftIO m
|
, MonadUnliftIO m
|
||||||
, MonadCatch m
|
, MonadCatch m
|
||||||
|
, MonadMask m
|
||||||
, HasCatAPI m
|
, HasCatAPI m
|
||||||
|
, HasImportOpts opts
|
||||||
)
|
)
|
||||||
=> Bool -> RepoRef -> m ()
|
=> opts -> RepoRef -> m ()
|
||||||
|
|
||||||
|
importRefLogNew opts ref = runResourceT do
|
||||||
|
|
||||||
|
let force = importForce opts
|
||||||
|
|
||||||
importRefLogNew force ref = runResourceT do
|
|
||||||
let myTempDir = "hbs-git"
|
let myTempDir = "hbs-git"
|
||||||
temp <- liftIO getCanonicalTemporaryDirectory
|
temp <- liftIO getCanonicalTemporaryDirectory
|
||||||
(_,dir) <- allocate (createTempDirectory temp myTempDir) removeDirectoryRecursive
|
(_,dir) <- allocate (createTempDirectory temp myTempDir) removeDirectoryRecursive
|
||||||
|
@ -232,8 +305,10 @@ importRefLogNew force ref = runResourceT do
|
||||||
|
|
||||||
_ -> pure ()
|
_ -> pure ()
|
||||||
|
|
||||||
statePutLogImported h
|
-- otherwise we wan't process those logs next time.
|
||||||
statePutTranImported e
|
unless (importDontWriteGit opts) do
|
||||||
|
statePutLogImported h
|
||||||
|
statePutTranImported e
|
||||||
|
|
||||||
mapM_ hClose handles
|
mapM_ hClose handles
|
||||||
|
|
||||||
|
@ -242,13 +317,13 @@ importRefLogNew force ref = runResourceT do
|
||||||
statePutRefImported logRoot
|
statePutRefImported logRoot
|
||||||
savepointRelease sp0
|
savepointRelease sp0
|
||||||
|
|
||||||
|
|
||||||
where
|
where
|
||||||
|
|
||||||
writeIfNew gitHandle dir h (GitObject tp s) = do
|
writeIfNew gitHandle dir h (GitObject tp s) = do
|
||||||
let nf = dir </> show (pretty h)
|
unless (importDontWriteGit opts) do
|
||||||
liftIO $ LBS.writeFile nf s
|
let nf = dir </> show (pretty h)
|
||||||
hPutStrLn gitHandle nf
|
liftIO $ LBS.writeFile nf s
|
||||||
hFlush gitHandle
|
hPutStrLn gitHandle nf
|
||||||
trace $ "WRITTEN OBJECT" <+> pretty tp <+> pretty h <+> pretty nf
|
hFlush gitHandle
|
||||||
|
trace $ "WRITTEN OBJECT" <+> pretty tp <+> pretty h <+> pretty nf
|
||||||
|
|
||||||
|
|
|
@ -73,14 +73,14 @@ runListRefs = do
|
||||||
where
|
where
|
||||||
isHbs2 (_, b) = Text.isPrefixOf hbs2Prefix b
|
isHbs2 (_, b) = Text.isPrefixOf hbs2Prefix b
|
||||||
|
|
||||||
runToolsScan :: (MonadUnliftIO m,MonadCatch m) => RepoRef -> App m ()
|
runToolsScan :: (MonadUnliftIO m,MonadCatch m,MonadMask m) => RepoRef -> App m ()
|
||||||
runToolsScan ref = do
|
runToolsScan ref = do
|
||||||
trace $ "runToolsScan" <+> pretty ref
|
trace $ "runToolsScan" <+> pretty ref
|
||||||
importRefLogNew False ref
|
importRefLogNew False ref
|
||||||
shutUp
|
shutUp
|
||||||
pure ()
|
pure ()
|
||||||
|
|
||||||
runToolsGetRefs :: (MonadUnliftIO m,MonadCatch m) => RepoRef -> App m ()
|
runToolsGetRefs :: (MonadUnliftIO m,MonadCatch m,MonadMask m) => RepoRef -> App m ()
|
||||||
runToolsGetRefs ref = do
|
runToolsGetRefs ref = do
|
||||||
db <- makeDbPath ref >>= dbEnv
|
db <- makeDbPath ref >>= dbEnv
|
||||||
refs <- withDB db stateGetActualRefs
|
refs <- withDB db stateGetActualRefs
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
module HBS2Git.State where
|
module HBS2Git.State where
|
||||||
|
|
||||||
|
import HBS2.Prelude
|
||||||
import HBS2Git.Types
|
import HBS2Git.Types
|
||||||
import HBS2.Data.Types.Refs
|
import HBS2.Data.Types.Refs
|
||||||
import HBS2.Git.Types
|
import HBS2.Git.Types
|
||||||
|
@ -7,6 +8,7 @@ import HBS2.Hash
|
||||||
|
|
||||||
import HBS2.System.Logger.Simple
|
import HBS2.System.Logger.Simple
|
||||||
|
|
||||||
|
import Control.Monad.Trans.Resource
|
||||||
import Data.Functor
|
import Data.Functor
|
||||||
import Data.Function
|
import Data.Function
|
||||||
import Database.SQLite.Simple
|
import Database.SQLite.Simple
|
||||||
|
@ -27,6 +29,7 @@ import Control.Concurrent.STM
|
||||||
import System.IO.Unsafe
|
import System.IO.Unsafe
|
||||||
import Data.Graph (graphFromEdges, topSort)
|
import Data.Graph (graphFromEdges, topSort)
|
||||||
import Data.Map qualified as Map
|
import Data.Map qualified as Map
|
||||||
|
import Lens.Micro.Platform
|
||||||
|
|
||||||
-- FIXME: move-orphans-to-separate-module
|
-- FIXME: move-orphans-to-separate-module
|
||||||
|
|
||||||
|
@ -61,7 +64,7 @@ newtype DB m a =
|
||||||
, Functor
|
, Functor
|
||||||
, Monad
|
, Monad
|
||||||
, MonadIO
|
, MonadIO
|
||||||
, MonadReader Connection
|
, MonadReader DBEnv
|
||||||
, MonadTrans
|
, MonadTrans
|
||||||
, MonadThrow
|
, MonadThrow
|
||||||
, MonadCatch
|
, MonadCatch
|
||||||
|
@ -71,32 +74,54 @@ instance (HasRefCredentials m) => HasRefCredentials (DB m) where
|
||||||
getCredentials = lift . getCredentials
|
getCredentials = lift . getCredentials
|
||||||
setCredentials r s = lift (setCredentials r s)
|
setCredentials r s = lift (setCredentials r s)
|
||||||
|
|
||||||
dbConnTV :: TVar (Maybe DBEnv)
|
stateConnection :: MonadIO m => DB m Connection
|
||||||
dbConnTV = unsafePerformIO $ newTVarIO Nothing
|
stateConnection = do
|
||||||
{-# NOINLINE dbConnTV #-}
|
env <- ask
|
||||||
|
initConnection env
|
||||||
|
|
||||||
dbEnv :: MonadIO m => FilePath -> m DBEnv
|
initConnection :: MonadIO m => DBEnv -> m Connection
|
||||||
dbEnv fp = do
|
initConnection env = do
|
||||||
|
mco <- liftIO $ readTVarIO (view dbConn env)
|
||||||
|
case mco of
|
||||||
|
Just co -> pure co
|
||||||
|
Nothing -> do
|
||||||
|
co <- liftIO $ open (view dbFilePath env)
|
||||||
|
liftIO $ atomically $ writeTVar (view dbConn env) (Just co)
|
||||||
|
pure co
|
||||||
|
|
||||||
|
dbEnv0 :: (MonadIO m, MonadMask m) => DB m () -> FilePath -> m DBEnv
|
||||||
|
dbEnv0 dbInit fp = do
|
||||||
trace "dbEnv called"
|
trace "dbEnv called"
|
||||||
let dir = takeDirectory fp
|
let dir = takeDirectory fp
|
||||||
liftIO $ createDirectoryIfMissing True dir
|
liftIO $ createDirectoryIfMissing True dir
|
||||||
mbDb <- liftIO $ readTVarIO dbConnTV
|
env <- DBEnv fp <$> liftIO (newTVarIO Nothing)
|
||||||
|
void $ withDB env dbInit
|
||||||
|
pure env
|
||||||
|
|
||||||
case mbDb of
|
dbEnv :: (MonadIO m, MonadMask m) => FilePath -> m DBEnv
|
||||||
Nothing -> do
|
dbEnv = dbEnv0 stateInit
|
||||||
co <- liftIO $ open fp
|
|
||||||
liftIO $ atomically $ writeTVar dbConnTV (Just co)
|
|
||||||
withDB co stateInit
|
|
||||||
pure co
|
|
||||||
|
|
||||||
Just db -> pure db
|
dbEnvReadOnly :: (MonadIO m, MonadMask m) => FilePath -> m DBEnv
|
||||||
|
dbEnvReadOnly = dbEnv0 none
|
||||||
|
|
||||||
withDB :: DBEnv -> DB m a -> m a
|
withDB :: (MonadIO m, MonadMask m) => DBEnv -> DB m a -> m a
|
||||||
withDB env action = runReaderT (fromDB action) env
|
withDB env action = do
|
||||||
|
conn <- initConnection env
|
||||||
|
finally (runReaderT (fromDB action) env) $ do
|
||||||
|
-- NOTE: we could not close connection here.
|
||||||
|
pure ()
|
||||||
|
|
||||||
|
shutdownDB :: MonadIO m => DBEnv -> m ()
|
||||||
|
shutdownDB env = liftIO do
|
||||||
|
co <- atomically do
|
||||||
|
conn <- readTVar (view dbConn env)
|
||||||
|
writeTVar (view dbConn env) Nothing
|
||||||
|
pure conn
|
||||||
|
maybe1 co none close
|
||||||
|
|
||||||
stateInit :: MonadIO m => DB m ()
|
stateInit :: MonadIO m => DB m ()
|
||||||
stateInit = do
|
stateInit = do
|
||||||
conn <- ask
|
conn <- stateConnection
|
||||||
liftIO $ execute_ conn [qc|
|
liftIO $ execute_ conn [qc|
|
||||||
create table if not exists logrefval
|
create table if not exists logrefval
|
||||||
( loghash text not null
|
( loghash text not null
|
||||||
|
@ -203,17 +228,17 @@ savepointNew = do
|
||||||
|
|
||||||
savepointBegin :: forall m . MonadIO m => Savepoint -> DB m ()
|
savepointBegin :: forall m . MonadIO m => Savepoint -> DB m ()
|
||||||
savepointBegin (Savepoint sp) = do
|
savepointBegin (Savepoint sp) = do
|
||||||
conn <- ask
|
conn <- stateConnection
|
||||||
liftIO $ execute_ conn [qc|SAVEPOINT {sp}|]
|
liftIO $ execute_ conn [qc|SAVEPOINT {sp}|]
|
||||||
|
|
||||||
savepointRelease:: forall m . MonadIO m => Savepoint -> DB m ()
|
savepointRelease:: forall m . MonadIO m => Savepoint -> DB m ()
|
||||||
savepointRelease (Savepoint sp) = do
|
savepointRelease (Savepoint sp) = do
|
||||||
conn <- ask
|
conn <- stateConnection
|
||||||
liftIO $ execute_ conn [qc|RELEASE SAVEPOINT {sp}|]
|
liftIO $ execute_ conn [qc|RELEASE SAVEPOINT {sp}|]
|
||||||
|
|
||||||
savepointRollback :: forall m . MonadIO m => Savepoint -> DB m ()
|
savepointRollback :: forall m . MonadIO m => Savepoint -> DB m ()
|
||||||
savepointRollback (Savepoint sp) = do
|
savepointRollback (Savepoint sp) = do
|
||||||
conn <- ask
|
conn <- stateConnection
|
||||||
liftIO $ execute_ conn [qc|ROLLBACK TO SAVEPOINT {sp}|]
|
liftIO $ execute_ conn [qc|ROLLBACK TO SAVEPOINT {sp}|]
|
||||||
|
|
||||||
transactional :: forall a m . (MonadCatch m, MonadIO m) => DB m a -> DB m a
|
transactional :: forall a m . (MonadCatch m, MonadIO m) => DB m a -> DB m a
|
||||||
|
@ -242,7 +267,7 @@ transactional action = do
|
||||||
|
|
||||||
statePutLogRefVal :: MonadIO m => (HashRef, GitRef, GitHash) -> DB m ()
|
statePutLogRefVal :: MonadIO m => (HashRef, GitRef, GitHash) -> DB m ()
|
||||||
statePutLogRefVal row = do
|
statePutLogRefVal row = do
|
||||||
conn <- ask
|
conn <- stateConnection
|
||||||
liftIO $ execute conn [qc|
|
liftIO $ execute conn [qc|
|
||||||
insert into logrefval (loghash,refname,refval) values(?,?,?)
|
insert into logrefval (loghash,refname,refval) values(?,?,?)
|
||||||
on conflict (loghash,refname) do nothing
|
on conflict (loghash,refname) do nothing
|
||||||
|
@ -251,7 +276,7 @@ statePutLogRefVal row = do
|
||||||
|
|
||||||
statePutLogObject :: MonadIO m => (HashRef, GitObjectType, GitHash) -> DB m ()
|
statePutLogObject :: MonadIO m => (HashRef, GitObjectType, GitHash) -> DB m ()
|
||||||
statePutLogObject row = do
|
statePutLogObject row = do
|
||||||
conn <- ask
|
conn <- stateConnection
|
||||||
liftIO $ execute conn [qc|
|
liftIO $ execute conn [qc|
|
||||||
insert into logobject (loghash,type,githash) values(?,?,?)
|
insert into logobject (loghash,type,githash) values(?,?,?)
|
||||||
on conflict (loghash,githash) do nothing
|
on conflict (loghash,githash) do nothing
|
||||||
|
@ -259,14 +284,24 @@ statePutLogObject row = do
|
||||||
|
|
||||||
stateIsLogObjectExists :: MonadIO m => GitHash -> DB m Bool
|
stateIsLogObjectExists :: MonadIO m => GitHash -> DB m Bool
|
||||||
stateIsLogObjectExists h = do
|
stateIsLogObjectExists h = do
|
||||||
conn <- ask
|
conn <- stateConnection
|
||||||
liftIO $ query conn [qc|
|
liftIO $ query conn [qc|
|
||||||
SELECT NULL FROM logobject WHERE githash = ? LIMIT 1
|
SELECT NULL FROM logobject WHERE githash = ? LIMIT 1
|
||||||
|] (Only h) <&> isJust . listToMaybe . fmap (fromOnly @(Maybe Int))
|
|] (Only h) <&> isJust . listToMaybe . fmap (fromOnly @(Maybe Int))
|
||||||
|
|
||||||
|
|
||||||
|
stateGetGitLogObject :: MonadIO m => GitHash -> DB m (Maybe HashRef)
|
||||||
|
stateGetGitLogObject h = do
|
||||||
|
conn <- stateConnection
|
||||||
|
liftIO $ query conn [qc|
|
||||||
|
SELECT loghash FROM logobject
|
||||||
|
WHERE githash = ? and type in ('commit', 'tree', 'blob')
|
||||||
|
LIMIT 1
|
||||||
|
|] (Only h) <&> listToMaybe . fmap fromOnly
|
||||||
|
|
||||||
statePutLogContextCommit :: MonadIO m => HashRef -> GitHash -> DB m ()
|
statePutLogContextCommit :: MonadIO m => HashRef -> GitHash -> DB m ()
|
||||||
statePutLogContextCommit loghash ctx = do
|
statePutLogContextCommit loghash ctx = do
|
||||||
conn <- ask
|
conn <- stateConnection
|
||||||
liftIO $ execute conn [qc|
|
liftIO $ execute conn [qc|
|
||||||
insert into logobject (loghash,type,githash) values(?,'context',?)
|
insert into logobject (loghash,type,githash) values(?,'context',?)
|
||||||
on conflict (loghash,githash) do nothing
|
on conflict (loghash,githash) do nothing
|
||||||
|
@ -274,7 +309,7 @@ statePutLogContextCommit loghash ctx = do
|
||||||
|
|
||||||
statePutLogCommitParent :: MonadIO m => (GitHash, GitHash) -> DB m ()
|
statePutLogCommitParent :: MonadIO m => (GitHash, GitHash) -> DB m ()
|
||||||
statePutLogCommitParent row = do
|
statePutLogCommitParent row = do
|
||||||
conn <- ask
|
conn <- stateConnection
|
||||||
liftIO $ execute conn [qc|
|
liftIO $ execute conn [qc|
|
||||||
insert into logcommitparent (kommit,parent) values(?,?)
|
insert into logcommitparent (kommit,parent) values(?,?)
|
||||||
on conflict (kommit,parent) do nothing
|
on conflict (kommit,parent) do nothing
|
||||||
|
@ -283,7 +318,7 @@ statePutLogCommitParent row = do
|
||||||
|
|
||||||
statePutLogImported :: MonadIO m => HashRef -> DB m ()
|
statePutLogImported :: MonadIO m => HashRef -> DB m ()
|
||||||
statePutLogImported h = do
|
statePutLogImported h = do
|
||||||
conn <- ask
|
conn <- stateConnection
|
||||||
liftIO $ execute conn [qc|
|
liftIO $ execute conn [qc|
|
||||||
insert into logimported (hash) values(?)
|
insert into logimported (hash) values(?)
|
||||||
on conflict (hash) do nothing
|
on conflict (hash) do nothing
|
||||||
|
@ -292,7 +327,7 @@ statePutLogImported h = do
|
||||||
|
|
||||||
stateGetLogImported :: MonadIO m => HashRef -> DB m Bool
|
stateGetLogImported :: MonadIO m => HashRef -> DB m Bool
|
||||||
stateGetLogImported h = do
|
stateGetLogImported h = do
|
||||||
conn <- ask
|
conn <- stateConnection
|
||||||
r <- liftIO $ query @_ @(Only Int) conn [qc|
|
r <- liftIO $ query @_ @(Only Int) conn [qc|
|
||||||
select 1 from logimported where hash = ? limit 1
|
select 1 from logimported where hash = ? limit 1
|
||||||
|] (Only h)
|
|] (Only h)
|
||||||
|
@ -301,7 +336,7 @@ stateGetLogImported h = do
|
||||||
|
|
||||||
statePutRefImported :: MonadIO m => HashRef -> DB m ()
|
statePutRefImported :: MonadIO m => HashRef -> DB m ()
|
||||||
statePutRefImported h = do
|
statePutRefImported h = do
|
||||||
conn <- ask
|
conn <- stateConnection
|
||||||
liftIO $ execute conn [qc|
|
liftIO $ execute conn [qc|
|
||||||
insert into refimported (hash) values(?)
|
insert into refimported (hash) values(?)
|
||||||
on conflict (hash) do nothing
|
on conflict (hash) do nothing
|
||||||
|
@ -309,7 +344,7 @@ statePutRefImported h = do
|
||||||
|
|
||||||
stateGetRefImported :: MonadIO m => HashRef -> DB m Bool
|
stateGetRefImported :: MonadIO m => HashRef -> DB m Bool
|
||||||
stateGetRefImported h = do
|
stateGetRefImported h = do
|
||||||
conn <- ask
|
conn <- stateConnection
|
||||||
r <- liftIO $ query @_ @(Only Int) conn [qc|
|
r <- liftIO $ query @_ @(Only Int) conn [qc|
|
||||||
select 1 from refimported where hash = ? limit 1
|
select 1 from refimported where hash = ? limit 1
|
||||||
|] (Only h)
|
|] (Only h)
|
||||||
|
@ -317,7 +352,7 @@ stateGetRefImported h = do
|
||||||
|
|
||||||
statePutTranImported :: MonadIO m => HashRef -> DB m ()
|
statePutTranImported :: MonadIO m => HashRef -> DB m ()
|
||||||
statePutTranImported h = do
|
statePutTranImported h = do
|
||||||
conn <- ask
|
conn <- stateConnection
|
||||||
liftIO $ execute conn [qc|
|
liftIO $ execute conn [qc|
|
||||||
insert into tranimported (hash) values(?)
|
insert into tranimported (hash) values(?)
|
||||||
on conflict (hash) do nothing
|
on conflict (hash) do nothing
|
||||||
|
@ -325,7 +360,7 @@ statePutTranImported h = do
|
||||||
|
|
||||||
stateGetTranImported :: MonadIO m => HashRef -> DB m Bool
|
stateGetTranImported :: MonadIO m => HashRef -> DB m Bool
|
||||||
stateGetTranImported h = do
|
stateGetTranImported h = do
|
||||||
conn <- ask
|
conn <- stateConnection
|
||||||
r <- liftIO $ query @_ @(Only Int) conn [qc|
|
r <- liftIO $ query @_ @(Only Int) conn [qc|
|
||||||
select 1 from tranimported where hash = ? limit 1
|
select 1 from tranimported where hash = ? limit 1
|
||||||
|] (Only h)
|
|] (Only h)
|
||||||
|
@ -333,7 +368,7 @@ stateGetTranImported h = do
|
||||||
|
|
||||||
stateGetAllTranImported :: MonadIO m => DB m [HashRef]
|
stateGetAllTranImported :: MonadIO m => DB m [HashRef]
|
||||||
stateGetAllTranImported = do
|
stateGetAllTranImported = do
|
||||||
conn <- ask
|
conn <- stateConnection
|
||||||
results <- liftIO $ query_ conn [qc|
|
results <- liftIO $ query_ conn [qc|
|
||||||
select hash from tranimported
|
select hash from tranimported
|
||||||
|]
|
|]
|
||||||
|
@ -341,21 +376,21 @@ stateGetAllTranImported = do
|
||||||
|
|
||||||
stateGetImportedCommits :: MonadIO m => DB m [GitHash]
|
stateGetImportedCommits :: MonadIO m => DB m [GitHash]
|
||||||
stateGetImportedCommits = do
|
stateGetImportedCommits = do
|
||||||
conn <- ask
|
conn <- stateConnection
|
||||||
liftIO $ query_ conn [qc|
|
liftIO $ query_ conn [qc|
|
||||||
select distinct(githash) from logobject where type = 'commit'
|
select distinct(githash) from logobject where type = 'commit'
|
||||||
|] <&> fmap fromOnly
|
|] <&> fmap fromOnly
|
||||||
|
|
||||||
stateGetActualRefs :: MonadIO m => DB m [(GitRef, GitHash)]
|
stateGetActualRefs :: MonadIO m => DB m [(GitRef, GitHash)]
|
||||||
stateGetActualRefs = do
|
stateGetActualRefs = do
|
||||||
conn <- ask
|
conn <- stateConnection
|
||||||
liftIO $ query_ conn [qc|
|
liftIO $ query_ conn [qc|
|
||||||
select refname,refval from v_refval_actual
|
select refname,refval from v_refval_actual
|
||||||
|]
|
|]
|
||||||
|
|
||||||
stateGetActualRefValue :: MonadIO m => GitRef -> DB m (Maybe GitHash)
|
stateGetActualRefValue :: MonadIO m => GitRef -> DB m (Maybe GitHash)
|
||||||
stateGetActualRefValue ref = do
|
stateGetActualRefValue ref = do
|
||||||
conn <- ask
|
conn <- stateConnection
|
||||||
liftIO $ query conn [qc|
|
liftIO $ query conn [qc|
|
||||||
select refval from v_refval_actual
|
select refval from v_refval_actual
|
||||||
where refname = ?
|
where refname = ?
|
||||||
|
@ -363,14 +398,14 @@ stateGetActualRefValue ref = do
|
||||||
|
|
||||||
stateGetLastKnownCommits :: MonadIO m => Int -> DB m [GitHash]
|
stateGetLastKnownCommits :: MonadIO m => Int -> DB m [GitHash]
|
||||||
stateGetLastKnownCommits n = do
|
stateGetLastKnownCommits n = do
|
||||||
conn <- ask
|
conn <- stateConnection
|
||||||
liftIO $ query conn [qc|
|
liftIO $ query conn [qc|
|
||||||
select kommit from logcommitdepth order by depth asc limit ?;
|
select kommit from logcommitdepth order by depth asc limit ?;
|
||||||
|] (Only n) <&> fmap fromOnly
|
|] (Only n) <&> fmap fromOnly
|
||||||
|
|
||||||
stateUpdateCommitDepths :: MonadIO m => DB m ()
|
stateUpdateCommitDepths :: MonadIO m => DB m ()
|
||||||
stateUpdateCommitDepths = do
|
stateUpdateCommitDepths = do
|
||||||
conn <- ask
|
conn <- stateConnection
|
||||||
sp <- savepointNew
|
sp <- savepointNew
|
||||||
|
|
||||||
rows <- liftIO $ query_ @(GitHash, GitHash) conn [qc|SELECT kommit, parent FROM logcommitparent|]
|
rows <- liftIO $ query_ @(GitHash, GitHash) conn [qc|SELECT kommit, parent FROM logcommitparent|]
|
||||||
|
|
|
@ -53,7 +53,12 @@ type HBS2L4Proto = L4Proto
|
||||||
-- FIXME: introduce-API-type
|
-- FIXME: introduce-API-type
|
||||||
type API = String
|
type API = String
|
||||||
|
|
||||||
type DBEnv = Connection
|
data DBEnv =
|
||||||
|
DBEnv { _dbFilePath :: FilePath
|
||||||
|
, _dbConn :: TVar (Maybe Connection)
|
||||||
|
}
|
||||||
|
|
||||||
|
makeLenses 'DBEnv
|
||||||
|
|
||||||
type RepoRef = RefLogKey Schema
|
type RepoRef = RefLogKey Schema
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue