diff options
author | Joey Hess <joey@kitenet.net> | 2010-11-08 16:47:36 -0400 |
---|---|---|
committer | Joey Hess <joey@kitenet.net> | 2010-11-08 17:00:34 -0400 |
commit | 6395b790ce3d2f97803f0c642af71d1a9eb169c6 (patch) | |
tree | 76ac64f2451d138e8cf476b5d66d2e4594686cdf | |
parent | ba59ac13b25d5be671e38cb7b4c40257f3fdac4f (diff) |
Reorganised the layout of .git/annex/
-rw-r--r-- | Core.hs | 77 | ||||
-rw-r--r-- | Locations.hs | 23 | ||||
-rw-r--r-- | debian/changelog | 10 | ||||
-rw-r--r-- | doc/git-annex.mdwn | 2 | ||||
-rw-r--r-- | test.hs | 4 |
5 files changed, 78 insertions, 38 deletions
@@ -25,6 +25,7 @@ import qualified Annex import qualified Backend import Utility import Messages +import Version {- Runs a list of Annex actions. Catches IO errors and continues - (but explicitly thrown errors terminate the whole command). @@ -54,16 +55,14 @@ startup = do {- When git-annex is done, it runs this. -} shutdown :: Annex Bool shutdown = do - g <- Annex.gitRepo - - -- Runs all queued git commands. q <- Annex.queueGet unless (q == GitQueue.empty) $ do - verbose $ liftIO $ putStrLn "Recording state in git..." - liftIO $ GitQueue.run g q + showSideAction "Recording state in git..." + Annex.queueRun -- clean up any files left in the temp directory, but leave -- the tmp directory itself + g <- Annex.gitRepo let tmp = annexTmpLocation g exists <- liftIO $ doesDirectoryExist tmp when (exists) $ liftIO $ removeDirectoryRecursive tmp @@ -140,13 +139,12 @@ logStatus key status = do getViaTmp :: Key -> (FilePath -> Annex Bool) -> Annex Bool getViaTmp key action = do g <- Annex.gitRepo - let dest = annexLocation g key let tmp = annexTmpLocation g ++ keyFile key liftIO $ createDirectoryIfMissing True (parentDir tmp) success <- action tmp if (success) then do - liftIO $ renameFile tmp dest + moveToObjectDir key tmp logStatus key ValuePresent return True else do @@ -154,17 +152,28 @@ getViaTmp key action = do -- to resume its transfer return False +{- Moves a file into .git/annex/objects/ -} +moveToObjectDir :: Key -> FilePath -> Annex () +moveToObjectDir key src = do + g <- Annex.gitRepo + let dest = annexLocation g key + liftIO $ createDirectoryIfMissing True (parentDir dest) + liftIO $ renameFile src dest + -- TODO directory and file mode tweaks + {- List of keys whose content exists in .git/annex/objects/ -} getKeysPresent :: Annex [Key] getKeysPresent = do g <- Annex.gitRepo - let top = annexObjectDir g - contents <- liftIO $ getDirectoryContents top - files <- liftIO $ filterM (isreg top) contents + getKeysPresent' $ annexObjectDir g +getKeysPresent' :: FilePath -> Annex [Key] +getKeysPresent' dir = do + contents <- liftIO $ getDirectoryContents dir + files <- liftIO $ filterM isreg contents return $ map fileKey files where - isreg top f = do - s <- getFileStatus $ top ++ "/" ++ f + isreg f = do + s <- getFileStatus $ dir ++ "/" ++ f return $ isRegularFile s {- List of keys referenced by symlinks in the git repo. -} @@ -178,17 +187,39 @@ getKeysReferenced = do {- Uses the annex.version git config setting to automate upgrades. -} autoUpgrade :: Annex () autoUpgrade = do + version <- getVersion + case version of + Just "0" -> upgradeFrom0 + Nothing -> return () -- repo not initted yet, no version + Just v | v == currentVersion -> return () + Just _ -> error "this version of git-annex is too old for this git repository!" + +upgradeFrom0 :: Annex () +upgradeFrom0 = do + showSideAction "Upgrading object directory layout for git-annex 0.04..." g <- Annex.gitRepo - case Git.configGet g field "0" of - "0" -> do -- before there was repo versioning - upgradeNote "Upgrading object directory layout..." - - setVersion - v | v == currentVersion -> return () - _ -> error "this version of git-annex is too old for this git repository!" + -- do the reorganisation of the files + let olddir = annexDir g + keys <- getKeysPresent' olddir + _ <- mapM (\k -> moveToObjectDir k $ olddir ++ "/" ++ keyFile k) keys + + -- update the symlinks to the files + files <- liftIO $ Git.inRepo g $ Git.workTree g + fixlinks files + Annex.queueRun + + setVersion + where - currentVersion = "1" - setVersion = Annex.setConfig field currentVersion - field = "annex.version" - upgradeNote s = verbose $ liftIO $ putStrLn $ "("++s++")" + fixlinks [] = return () + fixlinks (f:fs) = do + r <- Backend.lookupFile f + case r of + Nothing -> return () + Just (k, _) -> do + link <- calcGitLink f k + liftIO $ removeFile f + liftIO $ createSymbolicLink link f + Annex.queue "add" [] f + fixlinks fs diff --git a/Locations.hs b/Locations.hs index 78c0bff4b..e5f78a31c 100644 --- a/Locations.hs +++ b/Locations.hs @@ -14,7 +14,9 @@ module Locations ( annexLocationRelative, annexTmpLocation, annexDir, - annexObjectDir + annexObjectDir, + + prop_idempotent_fileKey ) where import Data.String.Utils @@ -29,12 +31,7 @@ stateLoc = ".git-annex/" gitStateDir :: Git.Repo -> FilePath gitStateDir repo = (Git.workTree repo) ++ "/" ++ stateLoc -{- An annexed file's content is stored in - - /path/to/repo/.git/annex/objects/<key>/<key>, where <key> is of the form - - <backend:fragment> - - - - That allows deriving the key and backend by looking at the symlink to it. - -} +{- Annexed file's absolute location. -} annexLocation :: Git.Repo -> Key -> FilePath annexLocation r key = (Git.workTree r) ++ "/" ++ (annexLocationRelative key) @@ -43,8 +40,9 @@ annexLocation r key = - - Note: Assumes repo is NOT bare.-} annexLocationRelative :: Key -> FilePath -annexLocationRelative key = ".git/annex/objects/" ++ f ++ f - where f = keyFile key +annexLocationRelative key = ".git/annex/objects/" ++ f ++ "/" ++ f + where + f = keyFile key {- The annex directory of a repository. - @@ -72,10 +70,15 @@ annexTmpLocation r = annexDir r ++ "/tmp/" - is one to one. - -} keyFile :: Key -> FilePath -keyFile key = replace "/" "%" $ replace "%" "&s" $ replace "&" "&a" $ show key +keyFile key = replace "/" "%" $ replace "%" "&s" $ replace "&" "&a" $ show key {- Reverses keyFile, converting a filename fragment (ie, the basename of - the symlink target) into a key. -} fileKey :: FilePath -> Key fileKey file = read $ replace "&a" "&" $ replace "&s" "%" $ replace "%" "/" file + +{- for quickcheck -} +prop_idempotent_fileKey :: String -> Bool +prop_idempotent_fileKey s = k == (fileKey $ keyFile k) + where k = read "test:s" diff --git a/debian/changelog b/debian/changelog index 49aa9829a..dc9dcedc2 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,9 +1,13 @@ git-annex (0.04) UNRELEASED; urgency=low * Add build dep on libghc6-testpack-dev. - * Add annex.version, which will be used to automate upgrades. - * Reorganised the layout of .git/annex/ , moving cached file contents - to .git/annex/objects/<key>/<key> + * Add annex.version, which will be used to automate upgrades + between incompatable versions. + * Reorganised the layout of .git/annex/ + * The new layout will be automatically upgraded to the first time + git-annex is used in a repository with the old layout. + * Note that git-annex 0.04 cannot transfer content from old repositories + that have not yet been upgraded. -- Joey Hess <joeyh@debian.org> Mon, 08 Nov 2010 12:36:39 -0400 diff --git a/doc/git-annex.mdwn b/doc/git-annex.mdwn index 6f2c85d57..6a580f005 100644 --- a/doc/git-annex.mdwn +++ b/doc/git-annex.mdwn @@ -223,7 +223,7 @@ but the SHA1 backend for ogg files: These files are used, in your git repository: -`.git/annex/` contains the annexed file contents that are currently +`.git/annex/objects/` contains the annexed file contents that are currently available. Annexed files in your git repository symlink to that content. `.git-annex/uuid.log` is used to map between repository UUID and @@ -5,9 +5,11 @@ import Test.HUnit import Test.HUnit.Tools import GitRepo +import Locations alltests = [ - qctest "prop_idempotent_deencode" prop_idempotent_deencode + qctest "prop_idempotent_deencode" prop_idempotent_deencode, + qctest "prop_idempotent_fileKey" prop_idempotent_fileKey ] main = runVerboseTests (TestList alltests) |