mirror of https://github.com/voidlizard/hbs2
rollback git state in case of exception
This commit is contained in:
parent
0f3bb22487
commit
0b12d6db79
|
@ -0,0 +1,2 @@
|
||||||
|
|
||||||
|
(fixme-set "workflow" "test" "E6RNxRxpnJ")
|
|
@ -40,7 +40,7 @@ import System.ProgressBar
|
||||||
import Text.InterpolatedString.Perl6 (qc)
|
import Text.InterpolatedString.Perl6 (qc)
|
||||||
import UnliftIO.IO as UIO
|
import UnliftIO.IO as UIO
|
||||||
import Control.Monad.Trans.Maybe
|
import Control.Monad.Trans.Maybe
|
||||||
|
import Control.Monad.Catch
|
||||||
|
|
||||||
send :: MonadIO m => BS.ByteString -> m ()
|
send :: MonadIO m => BS.ByteString -> m ()
|
||||||
send = liftIO . BS.hPutStr stdout
|
send = liftIO . BS.hPutStr stdout
|
||||||
|
@ -80,6 +80,7 @@ readHeadDef db =
|
||||||
readObject r <&> fromMaybe "\n"
|
readObject r <&> fromMaybe "\n"
|
||||||
|
|
||||||
loop :: forall m . ( MonadIO m
|
loop :: forall m . ( MonadIO m
|
||||||
|
, MonadCatch m
|
||||||
, HasProgress (RunWithConfig (GitRemoteApp m))
|
, HasProgress (RunWithConfig (GitRemoteApp m))
|
||||||
) => [String] -> GitRemoteApp m ()
|
) => [String] -> GitRemoteApp m ()
|
||||||
loop args = do
|
loop args = do
|
||||||
|
|
|
@ -31,6 +31,7 @@ import Text.InterpolatedString.Perl6 (qc)
|
||||||
import Data.ByteString qualified as BS
|
import Data.ByteString qualified as BS
|
||||||
import Control.Concurrent.STM.TVar
|
import Control.Concurrent.STM.TVar
|
||||||
import Control.Concurrent.STM
|
import Control.Concurrent.STM
|
||||||
|
import Control.Monad.Catch
|
||||||
|
|
||||||
newtype RunWithConfig m a =
|
newtype RunWithConfig m a =
|
||||||
WithConfig { fromWithConf :: ReaderT [Syntax C] m a }
|
WithConfig { fromWithConf :: ReaderT [Syntax C] m a }
|
||||||
|
@ -40,6 +41,8 @@ newtype RunWithConfig m a =
|
||||||
, MonadIO
|
, MonadIO
|
||||||
, MonadReader [Syntax C]
|
, MonadReader [Syntax C]
|
||||||
, MonadTrans
|
, MonadTrans
|
||||||
|
, MonadThrow
|
||||||
|
, MonadCatch
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ -60,6 +63,7 @@ instance MonadIO m => HasRefCredentials (RunWithConfig (GitRemoteApp m)) where
|
||||||
setCredentials r c = lift $ setCredentials r c
|
setCredentials r c = lift $ setCredentials r c
|
||||||
|
|
||||||
push :: forall m . ( MonadIO m
|
push :: forall m . ( MonadIO m
|
||||||
|
, MonadCatch m
|
||||||
, HasProgress (RunWithConfig (GitRemoteApp m))
|
, HasProgress (RunWithConfig (GitRemoteApp m))
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -13,6 +13,7 @@ import Lens.Micro.Platform
|
||||||
import Data.HashMap.Strict qualified as HashMap
|
import Data.HashMap.Strict qualified as HashMap
|
||||||
import Data.HashMap.Strict (HashMap)
|
import Data.HashMap.Strict (HashMap)
|
||||||
import Control.Concurrent.STM
|
import Control.Concurrent.STM
|
||||||
|
import Control.Monad.Catch
|
||||||
|
|
||||||
data RemoteEnv =
|
data RemoteEnv =
|
||||||
RemoteEnv
|
RemoteEnv
|
||||||
|
@ -32,6 +33,8 @@ newtype GitRemoteApp m a =
|
||||||
, Monad
|
, Monad
|
||||||
, MonadIO
|
, MonadIO
|
||||||
, MonadReader RemoteEnv
|
, MonadReader RemoteEnv
|
||||||
|
, MonadThrow
|
||||||
|
, MonadCatch
|
||||||
)
|
)
|
||||||
|
|
||||||
runRemoteM :: MonadIO m => RemoteEnv -> GitRemoteApp m a -> m a
|
runRemoteM :: MonadIO m => RemoteEnv -> GitRemoteApp m a -> m a
|
||||||
|
|
|
@ -82,6 +82,7 @@ common shared-properties
|
||||||
, unordered-containers
|
, unordered-containers
|
||||||
, filelock
|
, filelock
|
||||||
, http-conduit
|
, http-conduit
|
||||||
|
, exceptions
|
||||||
|
|
||||||
library
|
library
|
||||||
import: shared-properties
|
import: shared-properties
|
||||||
|
@ -102,8 +103,10 @@ library
|
||||||
-- other-modules:
|
-- other-modules:
|
||||||
-- other-extensions:
|
-- other-extensions:
|
||||||
build-depends: base
|
build-depends: base
|
||||||
, terminal-progress-bar
|
, exceptions
|
||||||
, http-types
|
, terminal-progress-bar
|
||||||
|
, http-types
|
||||||
|
, uuid
|
||||||
|
|
||||||
hs-source-dirs: lib
|
hs-source-dirs: lib
|
||||||
default-language: Haskell2010
|
default-language: Haskell2010
|
||||||
|
|
|
@ -52,6 +52,7 @@ import System.IO.Unsafe (unsafePerformIO)
|
||||||
import Data.Cache qualified as Cache
|
import Data.Cache qualified as Cache
|
||||||
import Control.Concurrent.Async
|
import Control.Concurrent.Async
|
||||||
import System.Environment
|
import System.Environment
|
||||||
|
import Control.Monad.Catch
|
||||||
|
|
||||||
instance MonadIO m => HasCfgKey ConfBranch (Set String) m where
|
instance MonadIO m => HasCfgKey ConfBranch (Set String) m where
|
||||||
key = "branch"
|
key = "branch"
|
||||||
|
|
|
@ -31,6 +31,7 @@ import Data.Set (Set)
|
||||||
import Lens.Micro.Platform
|
import Lens.Micro.Platform
|
||||||
import Control.Concurrent.STM
|
import Control.Concurrent.STM
|
||||||
import Control.Concurrent.Async
|
import Control.Concurrent.Async
|
||||||
|
import Control.Monad.Catch
|
||||||
|
|
||||||
data HashCache =
|
data HashCache =
|
||||||
HashCache
|
HashCache
|
||||||
|
@ -54,6 +55,7 @@ newHashCache db = do
|
||||||
|
|
||||||
|
|
||||||
export :: forall m . ( MonadIO m
|
export :: forall m . ( MonadIO m
|
||||||
|
, MonadCatch m
|
||||||
, HasCatAPI m
|
, HasCatAPI m
|
||||||
, HasConf m
|
, HasConf m
|
||||||
, HasRefCredentials m
|
, HasRefCredentials m
|
||||||
|
@ -175,7 +177,8 @@ export h repoHead = do
|
||||||
pure (HashRef root, hh)
|
pure (HashRef root, hh)
|
||||||
|
|
||||||
|
|
||||||
runExport :: forall m . (MonadIO m, HasProgress (App m)) => Maybe FilePath -> RepoRef -> App m ()
|
runExport :: forall m . (MonadIO m, MonadCatch m, HasProgress (App m))
|
||||||
|
=> Maybe FilePath -> RepoRef -> App m ()
|
||||||
runExport fp h = do
|
runExport fp h = do
|
||||||
|
|
||||||
trace $ "Export" <+> pretty (AsBase58 h)
|
trace $ "Export" <+> pretty (AsBase58 h)
|
||||||
|
|
|
@ -29,6 +29,7 @@ import Data.ByteString.Lazy qualified as LBS
|
||||||
import Lens.Micro.Platform
|
import Lens.Micro.Platform
|
||||||
-- import System.Exit
|
-- import System.Exit
|
||||||
import Codec.Serialise
|
import Codec.Serialise
|
||||||
|
import Control.Monad.Catch
|
||||||
|
|
||||||
data RunImportOpts =
|
data RunImportOpts =
|
||||||
RunImportOpts
|
RunImportOpts
|
||||||
|
@ -79,7 +80,7 @@ importRefLog db ref = do
|
||||||
when new do
|
when new do
|
||||||
pure ()
|
pure ()
|
||||||
|
|
||||||
importObjects :: (MonadIO m, HasCatAPI m) => DBEnv -> HashRef -> m ()
|
importObjects :: (MonadIO m, MonadCatch m, HasCatAPI m) => DBEnv -> HashRef -> m ()
|
||||||
importObjects db root = do
|
importObjects db root = do
|
||||||
|
|
||||||
q <- liftIO newTQueueIO
|
q <- liftIO newTQueueIO
|
||||||
|
|
|
@ -3,8 +3,10 @@ module HBS2Git.State where
|
||||||
import HBS2Git.Types
|
import HBS2Git.Types
|
||||||
import HBS2.Data.Types.Refs
|
import HBS2.Data.Types.Refs
|
||||||
import HBS2.Git.Types
|
import HBS2.Git.Types
|
||||||
|
import HBS2.Hash
|
||||||
|
|
||||||
import Data.Functor
|
import Data.Functor
|
||||||
|
import Data.Function
|
||||||
import Database.SQLite.Simple
|
import Database.SQLite.Simple
|
||||||
import Database.SQLite.Simple.FromField
|
import Database.SQLite.Simple.FromField
|
||||||
import Database.SQLite.Simple.ToField
|
import Database.SQLite.Simple.ToField
|
||||||
|
@ -12,11 +14,14 @@ import Control.Monad.IO.Class
|
||||||
import Control.Monad.Reader
|
import Control.Monad.Reader
|
||||||
import Text.InterpolatedString.Perl6 (qc)
|
import Text.InterpolatedString.Perl6 (qc)
|
||||||
import Data.String
|
import Data.String
|
||||||
|
import Data.ByteString.Lazy.Char8 qualified as LBS
|
||||||
import System.Directory
|
import System.Directory
|
||||||
import System.FilePath
|
import System.FilePath
|
||||||
import Data.Maybe
|
import Data.Maybe
|
||||||
import Data.Text (Text)
|
import Data.Text (Text)
|
||||||
import Prettyprinter
|
import Prettyprinter
|
||||||
|
import Data.UUID.V4 qualified as UUID
|
||||||
|
import Control.Monad.Catch
|
||||||
|
|
||||||
instance ToField GitHash where
|
instance ToField GitHash where
|
||||||
toField h = toField (show $ pretty h)
|
toField h = toField (show $ pretty h)
|
||||||
|
@ -46,10 +51,13 @@ newtype DB m a =
|
||||||
, MonadIO
|
, MonadIO
|
||||||
, MonadReader Connection
|
, MonadReader Connection
|
||||||
, MonadTrans
|
, MonadTrans
|
||||||
|
, MonadThrow
|
||||||
|
, MonadCatch
|
||||||
)
|
)
|
||||||
|
|
||||||
instance (HasRefCredentials m) => HasRefCredentials (DB m) where
|
instance (HasRefCredentials m) => HasRefCredentials (DB m) where
|
||||||
getCredentials = lift . getCredentials
|
getCredentials = lift . getCredentials
|
||||||
|
setCredentials r s = lift (setCredentials r s)
|
||||||
|
|
||||||
dbEnv :: MonadIO m => FilePath -> m DBEnv
|
dbEnv :: MonadIO m => FilePath -> m DBEnv
|
||||||
dbEnv fp = do
|
dbEnv fp = do
|
||||||
|
@ -109,13 +117,47 @@ stateInit = do
|
||||||
|]
|
|]
|
||||||
|
|
||||||
|
|
||||||
transactional :: forall a m . MonadIO m => DB m a -> DB m a
|
newtype Savepoint =
|
||||||
transactional action = do
|
Savepoint String
|
||||||
|
deriving newtype (IsString)
|
||||||
|
deriving stock (Eq,Ord)
|
||||||
|
|
||||||
|
savepointNew :: forall m . MonadIO m => DB m Savepoint
|
||||||
|
savepointNew = do
|
||||||
|
uu <- liftIO UUID.nextRandom
|
||||||
|
let s = LBS.pack (show uu) & hashObject @HbSync & pretty & show
|
||||||
|
pure $ fromString ("sp" <> s)
|
||||||
|
|
||||||
|
savepointBegin :: forall m . MonadIO m => Savepoint -> DB m ()
|
||||||
|
savepointBegin (Savepoint sp) = do
|
||||||
conn <- ask
|
conn <- ask
|
||||||
liftIO $ execute_ conn "begin"
|
liftIO $ execute_ conn [qc|SAVEPOINT {sp}|]
|
||||||
x <- action
|
|
||||||
liftIO $ execute_ conn "commit"
|
savepointRelease:: forall m . MonadIO m => Savepoint -> DB m ()
|
||||||
pure x
|
savepointRelease (Savepoint sp) = do
|
||||||
|
conn <- ask
|
||||||
|
liftIO $ execute_ conn [qc|RELEASE SAVEPOINT {sp}|]
|
||||||
|
|
||||||
|
savepointRollback :: forall m . MonadIO m => Savepoint -> DB m ()
|
||||||
|
savepointRollback (Savepoint sp) = do
|
||||||
|
conn <- ask
|
||||||
|
liftIO $ execute_ conn [qc|ROLLBACK TO SAVEPOINT {sp}|]
|
||||||
|
|
||||||
|
transactional :: forall a m . (MonadCatch m, MonadIO m) => DB m a -> DB m a
|
||||||
|
transactional action = do
|
||||||
|
|
||||||
|
sp <- savepointNew
|
||||||
|
|
||||||
|
savepointBegin sp
|
||||||
|
r <- try action
|
||||||
|
|
||||||
|
case r of
|
||||||
|
Left (e :: SomeException) -> do
|
||||||
|
savepointRollback sp
|
||||||
|
throwM e
|
||||||
|
|
||||||
|
Right x -> do
|
||||||
|
pure x
|
||||||
|
|
||||||
-- TODO: backlog-head-history
|
-- TODO: backlog-head-history
|
||||||
-- можно сделать таблицу history, в которую
|
-- можно сделать таблицу history, в которую
|
||||||
|
|
|
@ -33,6 +33,7 @@ import Control.Concurrent.STM
|
||||||
import System.IO qualified as IO
|
import System.IO qualified as IO
|
||||||
import System.IO (Handle)
|
import System.IO (Handle)
|
||||||
import Data.Kind
|
import Data.Kind
|
||||||
|
import Control.Monad.Catch
|
||||||
|
|
||||||
type Schema = UDP
|
type Schema = UDP
|
||||||
|
|
||||||
|
@ -142,7 +143,14 @@ class Monad m => HasConf m where
|
||||||
|
|
||||||
newtype App m a =
|
newtype App m a =
|
||||||
App { fromApp :: ReaderT AppEnv m a }
|
App { fromApp :: ReaderT AppEnv m a }
|
||||||
deriving newtype ( Applicative, Functor, Monad, MonadIO, MonadReader AppEnv )
|
deriving newtype ( Applicative
|
||||||
|
, Functor
|
||||||
|
, Monad
|
||||||
|
, MonadIO
|
||||||
|
, MonadReader AppEnv
|
||||||
|
, MonadThrow
|
||||||
|
, MonadCatch
|
||||||
|
)
|
||||||
|
|
||||||
instance MonadIO m => HasConf (App m) where
|
instance MonadIO m => HasConf (App m) where
|
||||||
getConf = asks (view appConf)
|
getConf = asks (view appConf)
|
||||||
|
|
|
@ -11,8 +11,10 @@ import HBS2Git.App
|
||||||
import HBS2Git.State
|
import HBS2Git.State
|
||||||
import HBS2Git.Import
|
import HBS2Git.Import
|
||||||
|
|
||||||
|
import Control.Monad.Catch
|
||||||
|
|
||||||
updateLocalState :: (MonadIO m, HasCatAPI m) => RepoRef -> m ()
|
|
||||||
|
updateLocalState :: (MonadIO m, HasCatAPI m, MonadCatch m) => RepoRef -> m ()
|
||||||
updateLocalState ref = do
|
updateLocalState ref = do
|
||||||
|
|
||||||
dbPath <- makeDbPath ref
|
dbPath <- makeDbPath ref
|
||||||
|
@ -23,15 +25,30 @@ updateLocalState ref = do
|
||||||
|
|
||||||
trace $ "updateLocalState" <+> pretty ref
|
trace $ "updateLocalState" <+> pretty ref
|
||||||
|
|
||||||
-- TODO: read-reflog
|
sp <- withDB db savepointNew
|
||||||
-- TODO: update-reflog
|
|
||||||
importRefLog db ref
|
|
||||||
|
|
||||||
(n,hash) <- withDB db $ stateGetRefLogLast `orDie` "empty reflog"
|
withDB db $ savepointBegin sp
|
||||||
|
|
||||||
trace $ "got reflog" <+> pretty (n,hash)
|
r <- try $ do
|
||||||
|
|
||||||
importObjects db hash
|
-- TODO: read-reflog
|
||||||
|
-- TODO: update-reflog
|
||||||
|
importRefLog db ref
|
||||||
|
|
||||||
|
(n,hash) <- withDB db $ stateGetRefLogLast `orDie` "empty reflog"
|
||||||
|
|
||||||
|
trace $ "got reflog" <+> pretty (n,hash)
|
||||||
|
|
||||||
|
importObjects db hash
|
||||||
|
|
||||||
|
withDB db (savepointRelease sp)
|
||||||
|
|
||||||
|
case r of
|
||||||
|
Left (e :: SomeException) -> do
|
||||||
|
withDB db $ savepointRollback sp
|
||||||
|
err (viaShow e)
|
||||||
|
err "error happened. state rolled back"
|
||||||
|
|
||||||
|
Right{} -> pure ()
|
||||||
|
|
||||||
pure ()
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue