Reorganised the layout of .git/annex/

This commit is contained in:
Joey Hess 2010-11-08 16:47:36 -04:00
parent ba59ac13b2
commit 6395b790ce
5 changed files with 78 additions and 38 deletions

77
Core.hs
View file

@ -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

View file

@ -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"

10
debian/changelog vendored
View file

@ -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

View file

@ -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

View file

@ -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)