diff options
author | Joey Hess <joey@kitenet.net> | 2014-02-19 14:14:44 -0400 |
---|---|---|
committer | Joey Hess <joey@kitenet.net> | 2014-02-19 14:17:58 -0400 |
commit | ade0216bd08c2f9c1ed10c1c2274fd5b071c9c93 (patch) | |
tree | 6097def98c91ec5a0b6b9a694ab5b4b4137063c0 /Annex | |
parent | 8d0b3f09a9effc71f729d5b820076c642b605eb4 (diff) |
pre-commit: Update metadata when committing changes to annexed files within a view.
So the user can now switch to a view and then move files around within it
to manage metadata. For example, moving a file into a new directory
when in the tags=* view adds a tag to it.
Implementation is fairly efficient. One diff-index, which is no more
expensive than the first stage of a git commit, followed by possibly
some cat-file --batch traffic to find the key (when deleting a file).
Very similar to what's done in direct mode when committing. And like
direct mode when updating the WC after a merge, it has to buffer the
diff-tree values in order to make 2 passes over them.
When not in a view, pre-commit now does one extra git symbolic-ref,
which is tiny overhead.
This commit was sponsored by Andrew Eskridge.
Diffstat (limited to 'Annex')
-rw-r--r-- | Annex/View.hs | 48 |
1 files changed, 45 insertions, 3 deletions
diff --git a/Annex/View.hs b/Annex/View.hs index 6db31ce92..abf8f073e 100644 --- a/Annex/View.hs +++ b/Annex/View.hs @@ -13,19 +13,25 @@ import Common.Annex import Types.View import Types.MetaData import qualified Git -import qualified Git.DiffTree +import qualified Git.DiffTree as DiffTree import qualified Git.Branch import qualified Git.LsFiles +import qualified Git.Ref import Git.UpdateIndex import Git.Sha import Git.HashObject import Git.Types +import Git.FilePath import qualified Backend import Annex.Index import Annex.Link +import Annex.CatFile import Logs.MetaData import Logs.View import Utility.FileMode +import Types.Command +import Config +import CmdLine.Action import qualified Data.Set as S import System.Path.WildMatch @@ -337,14 +343,50 @@ applyView' mkfileview view = do -} updateView :: View -> Git.Ref -> Git.Ref -> Annex Git.Branch updateView view ref oldref = genViewBranch view $ do - (diffs, cleanup) <- inRepo $ Git.DiffTree.diffTree oldref ref + (diffs, cleanup) <- inRepo $ DiffTree.diffTree oldref ref forM_ diffs go void $ liftIO cleanup where go diff - | Git.DiffTree.dstsha diff == nullSha = error "TODO delete file" + | DiffTree.dstsha diff == nullSha = error "TODO delete file" | otherwise = error "TODO add file" +{- Diff between currently checked out branch and staged changes, and + - update metadata to reflect the changes that are being committed to the + - view. + - + - Adding a file to a directory adds the metadata represented by + - that directory to the file, and removing a file from a directory + - removes the metadata. + - + - Note that removes must be handled before adds. This is so + - that moving a file from x/foo/ to x/bar/ adds back the metadata for x. + -} +withViewChanges :: (FileView -> Key -> CommandStart) -> (FileView -> Key -> CommandStart) -> Annex () +withViewChanges addmeta removemeta = do + makeabs <- flip fromTopFilePath <$> gitRepo + (diffs, cleanup) <- inRepo $ DiffTree.diffIndex Git.Ref.headRef + forM_ diffs handleremovals + forM_ diffs (handleadds makeabs) + void $ liftIO cleanup + where + handleremovals item + | DiffTree.srcsha item /= nullSha = + handle item removemeta + =<< catKey (DiffTree.srcsha item) (DiffTree.srcmode item) + | otherwise = noop + handleadds makeabs item + | DiffTree.dstsha item /= nullSha = + handle item addmeta + =<< ifM isDirect + ( catKey (DiffTree.dstsha item) (DiffTree.dstmode item) + -- optimisation + , isAnnexLink $ makeabs $ DiffTree.file item + ) + | otherwise = noop + handle item a = maybe noop + (void . commandAction . a (getTopFilePath $ DiffTree.file item)) + {- Generates a branch for a view. This is done using a different index - file. An action is run to stage the files that will be in the branch. - Then a commit is made, to the view branch. The view branch is not |