direct mode mappings now updated by git annex sync
Still lots to do to make sync handle direct mode, but this is a good first step.
This commit is contained in:
parent
715c67a3e5
commit
514957914d
2 changed files with 74 additions and 6 deletions
|
@ -7,6 +7,8 @@
|
||||||
|
|
||||||
module Annex.Content.Direct (
|
module Annex.Content.Direct (
|
||||||
associatedFiles,
|
associatedFiles,
|
||||||
|
changeAssociatedFiles,
|
||||||
|
updateAssociatedFiles,
|
||||||
goodContent,
|
goodContent,
|
||||||
updateCache,
|
updateCache,
|
||||||
recordedCache,
|
recordedCache,
|
||||||
|
@ -16,8 +18,14 @@ module Annex.Content.Direct (
|
||||||
|
|
||||||
import Common.Annex
|
import Common.Annex
|
||||||
import qualified Git
|
import qualified Git
|
||||||
|
import qualified Git.DiffTree as DiffTree
|
||||||
|
import Git.Sha
|
||||||
|
import Annex.CatFile
|
||||||
|
import Utility.TempFile
|
||||||
|
import Utility.FileMode
|
||||||
|
|
||||||
import System.Posix.Types
|
import System.Posix.Types
|
||||||
|
import qualified Data.ByteString.Lazy as L
|
||||||
|
|
||||||
{- Files in the tree that are associated with a key.
|
{- Files in the tree that are associated with a key.
|
||||||
-
|
-
|
||||||
|
@ -34,6 +42,45 @@ associatedFiles key = do
|
||||||
top <- fromRepo Git.repoPath
|
top <- fromRepo Git.repoPath
|
||||||
return $ map (top </>) files
|
return $ map (top </>) files
|
||||||
|
|
||||||
|
{- Changes the associated files information for a key, applying a
|
||||||
|
- transformation to the list. -}
|
||||||
|
changeAssociatedFiles :: Key -> ([FilePath] -> [FilePath]) -> Annex ()
|
||||||
|
changeAssociatedFiles key transform = do
|
||||||
|
mapping <- inRepo $ gitAnnexMapping key
|
||||||
|
liftIO $ do
|
||||||
|
files <- catchDefaultIO [] $ lines <$> readFile mapping
|
||||||
|
let files' = transform files
|
||||||
|
when (files /= files') $
|
||||||
|
viaTmp writeFile mapping $ unlines files'
|
||||||
|
|
||||||
|
removeAssociatedFile :: Key -> FilePath -> Annex ()
|
||||||
|
removeAssociatedFile key file = changeAssociatedFiles key $ filter (/= file)
|
||||||
|
|
||||||
|
addAssociatedFile :: Key -> FilePath -> Annex ()
|
||||||
|
addAssociatedFile key file = changeAssociatedFiles key $ \files ->
|
||||||
|
if file `elem` files
|
||||||
|
then files
|
||||||
|
else file:files
|
||||||
|
|
||||||
|
{- Uses git diff-tree to find files changed between two tree Shas, and
|
||||||
|
- updates the associated file mappings, efficiently -}
|
||||||
|
updateAssociatedFiles :: Git.Sha -> Git.Sha -> Annex ()
|
||||||
|
updateAssociatedFiles oldsha newsha = do
|
||||||
|
(items, cleanup) <- inRepo $ DiffTree.diffTree oldsha newsha
|
||||||
|
forM_ items update
|
||||||
|
void $ liftIO $ cleanup
|
||||||
|
where
|
||||||
|
update item = do
|
||||||
|
go DiffTree.dstsha DiffTree.dstmode addAssociatedFile
|
||||||
|
go DiffTree.srcsha DiffTree.srcmode removeAssociatedFile
|
||||||
|
where
|
||||||
|
go getsha getmode a =
|
||||||
|
when (getsha item /= nullSha && isSymLink (getmode item)) $ do
|
||||||
|
key <- getkey $ getsha item
|
||||||
|
maybe noop (\k -> a k $ DiffTree.file item) key
|
||||||
|
getkey sha = fileKey . takeFileName . encodeW8 . L.unpack
|
||||||
|
<$> catObject sha
|
||||||
|
|
||||||
{- Checks if a file in the tree, associated with a key, has not been modified.
|
{- Checks if a file in the tree, associated with a key, has not been modified.
|
||||||
-
|
-
|
||||||
- To avoid needing to fsck the file's content, which can involve an
|
- To avoid needing to fsck the file's content, which can involve an
|
||||||
|
@ -65,9 +112,6 @@ updateCache key file = withCacheFile key $ \cachefile ->
|
||||||
removeCache :: Key -> Annex ()
|
removeCache :: Key -> Annex ()
|
||||||
removeCache key = withCacheFile key nukeFile
|
removeCache key = withCacheFile key nukeFile
|
||||||
|
|
||||||
withCacheFile :: Key -> (FilePath -> IO a) -> Annex a
|
|
||||||
withCacheFile key a = liftIO . a =<< inRepo (gitAnnexCache key)
|
|
||||||
|
|
||||||
{- Cache a file's inode, size, and modification time to determine if it's
|
{- Cache a file's inode, size, and modification time to determine if it's
|
||||||
- been changed. -}
|
- been changed. -}
|
||||||
data Cache = Cache FileID FileOffset EpochTime
|
data Cache = Cache FileID FileOffset EpochTime
|
||||||
|
@ -98,3 +142,6 @@ toCache s
|
||||||
(fileSize s)
|
(fileSize s)
|
||||||
(modificationTime s)
|
(modificationTime s)
|
||||||
| otherwise = Nothing
|
| otherwise = Nothing
|
||||||
|
|
||||||
|
withCacheFile :: Key -> (FilePath -> IO a) -> Annex a
|
||||||
|
withCacheFile key a = liftIO . a =<< inRepo (gitAnnexCache key)
|
||||||
|
|
|
@ -15,6 +15,7 @@ import qualified Annex
|
||||||
import qualified Annex.Branch
|
import qualified Annex.Branch
|
||||||
import qualified Annex.Queue
|
import qualified Annex.Queue
|
||||||
import Annex.Content
|
import Annex.Content
|
||||||
|
import Annex.Content.Direct
|
||||||
import Annex.CatFile
|
import Annex.CatFile
|
||||||
import qualified Git.Command
|
import qualified Git.Command
|
||||||
import qualified Git.LsFiles as LsFiles
|
import qualified Git.LsFiles as LsFiles
|
||||||
|
@ -129,19 +130,39 @@ pullRemote remote branch = do
|
||||||
{- The remote probably has both a master and a synced/master branch.
|
{- The remote probably has both a master and a synced/master branch.
|
||||||
- Which to merge from? Well, the master has whatever latest changes
|
- Which to merge from? Well, the master has whatever latest changes
|
||||||
- were committed, while the synced/master may have changes that some
|
- were committed, while the synced/master may have changes that some
|
||||||
- other remote synced to this remote. So, merge them both. -}
|
- other remote synced to this remote. So, merge them both.
|
||||||
|
-
|
||||||
|
- In direct mode, updates associated files mappings for the files that
|
||||||
|
- were changed by the merge.
|
||||||
|
-}
|
||||||
mergeRemote :: Remote -> (Maybe Git.Ref) -> CommandCleanup
|
mergeRemote :: Remote -> (Maybe Git.Ref) -> CommandCleanup
|
||||||
mergeRemote remote b = case b of
|
mergeRemote remote b = case b of
|
||||||
Nothing -> do
|
Nothing -> do
|
||||||
branch <- inRepo Git.Branch.currentUnsafe
|
branch <- inRepo Git.Branch.currentUnsafe
|
||||||
all id <$> (mapM merge $ branchlist branch)
|
update branch $
|
||||||
Just _ -> all id <$> (mapM merge =<< tomerge (branchlist b))
|
all id <$> (mapM merge $ branchlist branch)
|
||||||
|
Just branch -> update (Just branch) $
|
||||||
|
all id <$> (mapM merge =<< tomerge (branchlist b))
|
||||||
where
|
where
|
||||||
merge = mergeFrom . remoteBranch remote
|
merge = mergeFrom . remoteBranch remote
|
||||||
tomerge branches = filterM (changed remote) branches
|
tomerge branches = filterM (changed remote) branches
|
||||||
branchlist Nothing = []
|
branchlist Nothing = []
|
||||||
branchlist (Just branch) = [branch, syncBranch branch]
|
branchlist (Just branch) = [branch, syncBranch branch]
|
||||||
|
|
||||||
|
update Nothing a = a
|
||||||
|
update (Just branch) a = ifM isDirect
|
||||||
|
( do
|
||||||
|
old <- inRepo $ Git.Ref.sha branch
|
||||||
|
r <- a
|
||||||
|
new <- inRepo $ Git.Ref.sha branch
|
||||||
|
case (old, new) of
|
||||||
|
(Just oldsha, Just newsha) -> do
|
||||||
|
updateAssociatedFiles oldsha newsha
|
||||||
|
_ -> noop
|
||||||
|
return r
|
||||||
|
, a
|
||||||
|
)
|
||||||
|
|
||||||
pushRemote :: Remote -> Git.Ref -> CommandStart
|
pushRemote :: Remote -> Git.Ref -> CommandStart
|
||||||
pushRemote remote branch = go =<< needpush
|
pushRemote remote branch = go =<< needpush
|
||||||
where
|
where
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue