Reorganised the layout of .git/annex/
This commit is contained in:
parent
ba59ac13b2
commit
6395b790ce
5 changed files with 78 additions and 38 deletions
77
Core.hs
77
Core.hs
|
@ -25,6 +25,7 @@ import qualified Annex
|
||||||
import qualified Backend
|
import qualified Backend
|
||||||
import Utility
|
import Utility
|
||||||
import Messages
|
import Messages
|
||||||
|
import Version
|
||||||
|
|
||||||
{- Runs a list of Annex actions. Catches IO errors and continues
|
{- Runs a list of Annex actions. Catches IO errors and continues
|
||||||
- (but explicitly thrown errors terminate the whole command).
|
- (but explicitly thrown errors terminate the whole command).
|
||||||
|
@ -54,16 +55,14 @@ startup = do
|
||||||
{- When git-annex is done, it runs this. -}
|
{- When git-annex is done, it runs this. -}
|
||||||
shutdown :: Annex Bool
|
shutdown :: Annex Bool
|
||||||
shutdown = do
|
shutdown = do
|
||||||
g <- Annex.gitRepo
|
|
||||||
|
|
||||||
-- Runs all queued git commands.
|
|
||||||
q <- Annex.queueGet
|
q <- Annex.queueGet
|
||||||
unless (q == GitQueue.empty) $ do
|
unless (q == GitQueue.empty) $ do
|
||||||
verbose $ liftIO $ putStrLn "Recording state in git..."
|
showSideAction "Recording state in git..."
|
||||||
liftIO $ GitQueue.run g q
|
Annex.queueRun
|
||||||
|
|
||||||
-- clean up any files left in the temp directory, but leave
|
-- clean up any files left in the temp directory, but leave
|
||||||
-- the tmp directory itself
|
-- the tmp directory itself
|
||||||
|
g <- Annex.gitRepo
|
||||||
let tmp = annexTmpLocation g
|
let tmp = annexTmpLocation g
|
||||||
exists <- liftIO $ doesDirectoryExist tmp
|
exists <- liftIO $ doesDirectoryExist tmp
|
||||||
when (exists) $ liftIO $ removeDirectoryRecursive tmp
|
when (exists) $ liftIO $ removeDirectoryRecursive tmp
|
||||||
|
@ -140,13 +139,12 @@ logStatus key status = do
|
||||||
getViaTmp :: Key -> (FilePath -> Annex Bool) -> Annex Bool
|
getViaTmp :: Key -> (FilePath -> Annex Bool) -> Annex Bool
|
||||||
getViaTmp key action = do
|
getViaTmp key action = do
|
||||||
g <- Annex.gitRepo
|
g <- Annex.gitRepo
|
||||||
let dest = annexLocation g key
|
|
||||||
let tmp = annexTmpLocation g ++ keyFile key
|
let tmp = annexTmpLocation g ++ keyFile key
|
||||||
liftIO $ createDirectoryIfMissing True (parentDir tmp)
|
liftIO $ createDirectoryIfMissing True (parentDir tmp)
|
||||||
success <- action tmp
|
success <- action tmp
|
||||||
if (success)
|
if (success)
|
||||||
then do
|
then do
|
||||||
liftIO $ renameFile tmp dest
|
moveToObjectDir key tmp
|
||||||
logStatus key ValuePresent
|
logStatus key ValuePresent
|
||||||
return True
|
return True
|
||||||
else do
|
else do
|
||||||
|
@ -154,17 +152,28 @@ getViaTmp key action = do
|
||||||
-- to resume its transfer
|
-- to resume its transfer
|
||||||
return False
|
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/ -}
|
{- List of keys whose content exists in .git/annex/objects/ -}
|
||||||
getKeysPresent :: Annex [Key]
|
getKeysPresent :: Annex [Key]
|
||||||
getKeysPresent = do
|
getKeysPresent = do
|
||||||
g <- Annex.gitRepo
|
g <- Annex.gitRepo
|
||||||
let top = annexObjectDir g
|
getKeysPresent' $ annexObjectDir g
|
||||||
contents <- liftIO $ getDirectoryContents top
|
getKeysPresent' :: FilePath -> Annex [Key]
|
||||||
files <- liftIO $ filterM (isreg top) contents
|
getKeysPresent' dir = do
|
||||||
|
contents <- liftIO $ getDirectoryContents dir
|
||||||
|
files <- liftIO $ filterM isreg contents
|
||||||
return $ map fileKey files
|
return $ map fileKey files
|
||||||
where
|
where
|
||||||
isreg top f = do
|
isreg f = do
|
||||||
s <- getFileStatus $ top ++ "/" ++ f
|
s <- getFileStatus $ dir ++ "/" ++ f
|
||||||
return $ isRegularFile s
|
return $ isRegularFile s
|
||||||
|
|
||||||
{- List of keys referenced by symlinks in the git repo. -}
|
{- 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. -}
|
{- Uses the annex.version git config setting to automate upgrades. -}
|
||||||
autoUpgrade :: Annex ()
|
autoUpgrade :: Annex ()
|
||||||
autoUpgrade = do
|
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
|
g <- Annex.gitRepo
|
||||||
|
|
||||||
case Git.configGet g field "0" of
|
-- do the reorganisation of the files
|
||||||
"0" -> do -- before there was repo versioning
|
let olddir = annexDir g
|
||||||
upgradeNote "Upgrading object directory layout..."
|
keys <- getKeysPresent' olddir
|
||||||
|
_ <- mapM (\k -> moveToObjectDir k $ olddir ++ "/" ++ keyFile k) keys
|
||||||
setVersion
|
|
||||||
v | v == currentVersion -> return ()
|
-- update the symlinks to the files
|
||||||
_ -> error "this version of git-annex is too old for this git repository!"
|
files <- liftIO $ Git.inRepo g $ Git.workTree g
|
||||||
|
fixlinks files
|
||||||
|
Annex.queueRun
|
||||||
|
|
||||||
|
setVersion
|
||||||
|
|
||||||
where
|
where
|
||||||
currentVersion = "1"
|
fixlinks [] = return ()
|
||||||
setVersion = Annex.setConfig field currentVersion
|
fixlinks (f:fs) = do
|
||||||
field = "annex.version"
|
r <- Backend.lookupFile f
|
||||||
upgradeNote s = verbose $ liftIO $ putStrLn $ "("++s++")"
|
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
|
||||||
|
|
23
Locations.hs
23
Locations.hs
|
@ -14,7 +14,9 @@ module Locations (
|
||||||
annexLocationRelative,
|
annexLocationRelative,
|
||||||
annexTmpLocation,
|
annexTmpLocation,
|
||||||
annexDir,
|
annexDir,
|
||||||
annexObjectDir
|
annexObjectDir,
|
||||||
|
|
||||||
|
prop_idempotent_fileKey
|
||||||
) where
|
) where
|
||||||
|
|
||||||
import Data.String.Utils
|
import Data.String.Utils
|
||||||
|
@ -29,12 +31,7 @@ stateLoc = ".git-annex/"
|
||||||
gitStateDir :: Git.Repo -> FilePath
|
gitStateDir :: Git.Repo -> FilePath
|
||||||
gitStateDir repo = (Git.workTree repo) ++ "/" ++ stateLoc
|
gitStateDir repo = (Git.workTree repo) ++ "/" ++ stateLoc
|
||||||
|
|
||||||
{- An annexed file's content is stored in
|
{- Annexed file's absolute location. -}
|
||||||
- /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.
|
|
||||||
-}
|
|
||||||
annexLocation :: Git.Repo -> Key -> FilePath
|
annexLocation :: Git.Repo -> Key -> FilePath
|
||||||
annexLocation r key =
|
annexLocation r key =
|
||||||
(Git.workTree r) ++ "/" ++ (annexLocationRelative key)
|
(Git.workTree r) ++ "/" ++ (annexLocationRelative key)
|
||||||
|
@ -43,8 +40,9 @@ annexLocation r key =
|
||||||
-
|
-
|
||||||
- Note: Assumes repo is NOT bare.-}
|
- Note: Assumes repo is NOT bare.-}
|
||||||
annexLocationRelative :: Key -> FilePath
|
annexLocationRelative :: Key -> FilePath
|
||||||
annexLocationRelative key = ".git/annex/objects/" ++ f ++ f
|
annexLocationRelative key = ".git/annex/objects/" ++ f ++ "/" ++ f
|
||||||
where f = keyFile key
|
where
|
||||||
|
f = keyFile key
|
||||||
|
|
||||||
{- The annex directory of a repository.
|
{- The annex directory of a repository.
|
||||||
-
|
-
|
||||||
|
@ -72,10 +70,15 @@ annexTmpLocation r = annexDir r ++ "/tmp/"
|
||||||
- is one to one.
|
- is one to one.
|
||||||
- -}
|
- -}
|
||||||
keyFile :: Key -> FilePath
|
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
|
{- Reverses keyFile, converting a filename fragment (ie, the basename of
|
||||||
- the symlink target) into a key. -}
|
- the symlink target) into a key. -}
|
||||||
fileKey :: FilePath -> Key
|
fileKey :: FilePath -> Key
|
||||||
fileKey file = read $
|
fileKey file = read $
|
||||||
replace "&a" "&" $ replace "&s" "%" $ replace "%" "/" file
|
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
10
debian/changelog
vendored
|
@ -1,9 +1,13 @@
|
||||||
git-annex (0.04) UNRELEASED; urgency=low
|
git-annex (0.04) UNRELEASED; urgency=low
|
||||||
|
|
||||||
* Add build dep on libghc6-testpack-dev.
|
* Add build dep on libghc6-testpack-dev.
|
||||||
* Add annex.version, which will be used to automate upgrades.
|
* Add annex.version, which will be used to automate upgrades
|
||||||
* Reorganised the layout of .git/annex/ , moving cached file contents
|
between incompatable versions.
|
||||||
to .git/annex/objects/<key>/<key>
|
* 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
|
-- Joey Hess <joeyh@debian.org> Mon, 08 Nov 2010 12:36:39 -0400
|
||||||
|
|
||||||
|
|
|
@ -223,7 +223,7 @@ but the SHA1 backend for ogg files:
|
||||||
|
|
||||||
These files are used, in your git repository:
|
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.
|
available. Annexed files in your git repository symlink to that content.
|
||||||
|
|
||||||
`.git-annex/uuid.log` is used to map between repository UUID and
|
`.git-annex/uuid.log` is used to map between repository UUID and
|
||||||
|
|
4
test.hs
4
test.hs
|
@ -5,9 +5,11 @@ import Test.HUnit
|
||||||
import Test.HUnit.Tools
|
import Test.HUnit.Tools
|
||||||
|
|
||||||
import GitRepo
|
import GitRepo
|
||||||
|
import Locations
|
||||||
|
|
||||||
alltests = [
|
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)
|
main = runVerboseTests (TestList alltests)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue