do a cleanup commit after moving data from or to a git remote

Added Annex.cleanup, which is a general purpose interface for adding
actions to run at the end.

Remotes with the old git-annex-shell will commit every time, and have no
commit command, so hide stderr when running the commit command.
This commit is contained in:
Joey Hess 2012-02-25 18:02:49 -04:00
parent a3c9d06a26
commit c3fbe07d7a
5 changed files with 43 additions and 13 deletions

View file

@ -21,6 +21,7 @@ module Annex (
setField, setField,
getFlag, getFlag,
getField, getField,
addCleanup,
gitRepo, gitRepo,
inRepo, inRepo,
fromRepo, fromRepo,
@ -93,6 +94,7 @@ data AnnexState = AnnexState
, lockpool :: M.Map FilePath Fd , lockpool :: M.Map FilePath Fd
, flags :: M.Map String Bool , flags :: M.Map String Bool
, fields :: M.Map String String , fields :: M.Map String String
, cleanup :: M.Map String (Annex ())
} }
newState :: Git.Repo -> AnnexState newState :: Git.Repo -> AnnexState
@ -117,6 +119,7 @@ newState gitrepo = AnnexState
, lockpool = M.empty , lockpool = M.empty
, flags = M.empty , flags = M.empty
, fields = M.empty , fields = M.empty
, cleanup = M.empty
} }
{- Create and returns an Annex state object for the specified git repo. -} {- Create and returns an Annex state object for the specified git repo. -}
@ -132,12 +135,17 @@ eval s a = evalStateT (runAnnex a) s
{- Sets a flag to True -} {- Sets a flag to True -}
setFlag :: String -> Annex () setFlag :: String -> Annex ()
setFlag flag = changeState $ \s -> setFlag flag = changeState $ \s ->
s { flags = M.insert flag True $ flags s } s { flags = M.insertWith' const flag True $ flags s }
{- Sets a field to a value -} {- Sets a field to a value -}
setField :: String -> String -> Annex () setField :: String -> String -> Annex ()
setField field value = changeState $ \s -> setField field value = changeState $ \s ->
s { fields = M.insert field value $ fields s } s { fields = M.insertWith' const field value $ fields s }
{- Adds a cleanup action to perform. -}
addCleanup :: String -> Annex () -> Annex ()
addCleanup uid a = changeState $ \s ->
s { cleanup = M.insertWith' const uid a $ cleanup s }
{- Checks if a flag was set. -} {- Checks if a flag was set. -}
getFlag :: String -> Annex Bool getFlag :: String -> Annex Bool

View file

@ -12,6 +12,7 @@ module CmdLine (
) where ) where
import qualified Control.Exception as E import qualified Control.Exception as E
import qualified Data.Map as M
import Control.Exception (throw) import Control.Exception (throw)
import System.Console.GetOpt import System.Console.GetOpt
@ -95,6 +96,7 @@ startup = return True
shutdown :: Bool -> Annex Bool shutdown :: Bool -> Annex Bool
shutdown oneshot = do shutdown oneshot = do
saveState oneshot saveState oneshot
sequence_ =<< M.elems <$> Annex.getState Annex.cleanup
liftIO Git.Command.reap -- zombies from long-running git processes liftIO Git.Command.reap -- zombies from long-running git processes
sshCleanup -- ssh connection caching sshCleanup -- ssh connection caching
return True return True

View file

@ -1,6 +1,6 @@
{- Standard git remotes. {- Standard git remotes.
- -
- Copyright 2011 Joey Hess <joey@kitenet.net> - Copyright 2011-2012 Joey Hess <joey@kitenet.net>
- -
- Licensed under the GNU GPL version 3 or higher. - Licensed under the GNU GPL version 3 or higher.
-} -}
@ -24,6 +24,7 @@ import Logs.Presence
import Annex.UUID import Annex.UUID
import qualified Annex.Content import qualified Annex.Content
import qualified Annex.BranchState import qualified Annex.BranchState
import qualified Annex.Branch
import qualified Utility.Url as Url import qualified Utility.Url as Url
import Utility.TempFile import Utility.TempFile
import Config import Config
@ -196,7 +197,7 @@ keyUrls r key = map tourl (annexLocations key)
dropKey :: Git.Repo -> Key -> Annex Bool dropKey :: Git.Repo -> Key -> Annex Bool
dropKey r key dropKey r key
| not $ Git.repoIsUrl r = liftIO $ onLocal r $ do | not $ Git.repoIsUrl r = commitOnCleanup r $ liftIO $ onLocal r $ do
ensureInitialized ensureInitialized
whenM (Annex.Content.inAnnex key) $ do whenM (Annex.Content.inAnnex key) $ do
Annex.Content.lockContent key $ Annex.Content.lockContent key $
@ -205,7 +206,7 @@ dropKey r key
Annex.Content.saveState True Annex.Content.saveState True
return True return True
| Git.repoIsHttp r = error "dropping from http repo not supported" | Git.repoIsHttp r = error "dropping from http repo not supported"
| otherwise = onRemote r (boolSystem, False) "dropkey" | otherwise = commitOnCleanup r $ onRemote r (boolSystem, False) "dropkey"
[ Params "--quiet --force" [ Params "--quiet --force"
, Param $ show key , Param $ show key
] ]
@ -236,7 +237,7 @@ copyFromRemoteCheap r key file
{- Tries to copy a key's content to a remote's annex. -} {- Tries to copy a key's content to a remote's annex. -}
copyToRemote :: Git.Repo -> Key -> Annex Bool copyToRemote :: Git.Repo -> Key -> Annex Bool
copyToRemote r key copyToRemote r key
| not $ Git.repoIsUrl r = do | not $ Git.repoIsUrl r = commitOnCleanup r $ do
keysrc <- inRepo $ gitAnnexLocation key keysrc <- inRepo $ gitAnnexLocation key
params <- rsyncParams r params <- rsyncParams r
-- run copy from perspective of remote -- run copy from perspective of remote
@ -245,7 +246,7 @@ copyToRemote r key
Annex.Content.saveState True `after` Annex.Content.saveState True `after`
Annex.Content.getViaTmp key Annex.Content.getViaTmp key
(rsyncOrCopyFile params keysrc) (rsyncOrCopyFile params keysrc)
| Git.repoIsSsh r = do | Git.repoIsSsh r = commitOnCleanup r $ do
keysrc <- inRepo $ gitAnnexLocation key keysrc <- inRepo $ gitAnnexLocation key
rsyncHelper =<< rsyncParamsRemote r False key keysrc rsyncHelper =<< rsyncParamsRemote r False key keysrc
| otherwise = error "copying to non-ssh repo not supported" | otherwise = error "copying to non-ssh repo not supported"
@ -301,3 +302,23 @@ rsyncParams r = do
where where
-- --inplace to resume partial files -- --inplace to resume partial files
options = [Params "-p --progress --inplace"] options = [Params "-p --progress --inplace"]
commitOnCleanup :: Git.Repo -> Annex a -> Annex a
commitOnCleanup r a = go `after` a
where
go = Annex.addCleanup (Git.repoLocation r) cleanup
cleanup
| not $ Git.repoIsUrl r = liftIO $ onLocal r $
Annex.Branch.commit "update"
| otherwise = do
Just (shellcmd, shellparams) <-
git_annex_shell r "commit" []
-- Throw away stderr, since the remote may not
-- have a new enough git-annex shell to
-- support committing.
let cmd = shellcmd ++ " "
++ unwords (map shellEscape $ toCommand shellparams)
++ ">/dev/null 2>/dev/null"
_ <- liftIO $
boolSystem "sh" [Param "-c", Param cmd]
return ()

8
debian/changelog vendored
View file

@ -29,12 +29,8 @@ git-annex (3.20120124) UNRELEASED; urgency=low
* Store web special remote url info in a more efficient location. * Store web special remote url info in a more efficient location.
* Deal with NFS problem that caused a failure to remove a directory * Deal with NFS problem that caused a failure to remove a directory
when removing content from the annex. when removing content from the annex.
* Avoid repeated location log commits when a remote is receiving files. * Make a single location log commit after a remote has received or
Done by adding a oneshot mode, in which location log changes are dropped files. Uses a new "git-annex-shell commit" command.
written to the journal, but not committed. Taking advantage of
git-annex's existing ability to recover in this situation. This is
used by git-annex-shell and other places where changes are made to
a remote's location log.
* To avoid commits of data to the git-annex branch after each command * To avoid commits of data to the git-annex branch after each command
is run, set annex.alwayscommit=false. Its data will then be committed is run, set annex.alwayscommit=false. Its data will then be committed
less frequently, when a merge or sync is done. less frequently, when a merge or sync is done.

View file

@ -33,3 +33,6 @@ are local. It seems to be just overhead.)
Oneshot mode is now implemented, making git-annex-shell and other Oneshot mode is now implemented, making git-annex-shell and other
short lifetime processes not bother with committing changes. short lifetime processes not bother with committing changes.
[[done]] --[[Joey]] [[done]] --[[Joey]]
Update: Now it makes one commit at the very end of such a mass transfer.
--[[Joey]]