summaryrefslogtreecommitdiff
path: root/Annex
diff options
context:
space:
mode:
authorGravatar Joey Hess <joey@kitenet.net>2014-02-19 14:14:44 -0400
committerGravatar Joey Hess <joey@kitenet.net>2014-02-19 14:17:58 -0400
commitade0216bd08c2f9c1ed10c1c2274fd5b071c9c93 (patch)
tree6097def98c91ec5a0b6b9a694ab5b4b4137063c0 /Annex
parent8d0b3f09a9effc71f729d5b820076c642b605eb4 (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.hs48
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