start to support core.symlinks=false
Utility functions to handle no symlink mode, and converted Annex.Content to use them; still many other places to convert.
This commit is contained in:
parent
2cd696a124
commit
5ea4b91fb4
4 changed files with 81 additions and 52 deletions
|
@ -50,6 +50,7 @@ import Annex.Exception
|
||||||
import Git.SharedRepository
|
import Git.SharedRepository
|
||||||
import Annex.Perms
|
import Annex.Perms
|
||||||
import Annex.Content.Direct
|
import Annex.Content.Direct
|
||||||
|
import Backend
|
||||||
|
|
||||||
{- Checks if a given key's content is currently present. -}
|
{- Checks if a given key's content is currently present. -}
|
||||||
inAnnex :: Key -> Annex Bool
|
inAnnex :: Key -> Annex Bool
|
||||||
|
@ -248,33 +249,27 @@ moveAnnex key src = withObjectLoc key storeobject storedirect
|
||||||
freezeContent dest
|
freezeContent dest
|
||||||
freezeContentDir dest
|
freezeContentDir dest
|
||||||
)
|
)
|
||||||
storedirect fs = storedirect' =<< liftIO (filterM validsymlink fs)
|
storedirect fs = storedirect' =<< filterM validsymlink fs
|
||||||
|
validsymlink f = (==) (Just key) <$> isAnnexLink f
|
||||||
validsymlink f = do
|
|
||||||
tl <- tryIO $ readSymbolicLink f
|
|
||||||
return $ case tl of
|
|
||||||
Right l
|
|
||||||
| isLinkToAnnex l ->
|
|
||||||
Just key == fileKey (takeFileName l)
|
|
||||||
_ -> False
|
|
||||||
|
|
||||||
storedirect' [] = storeobject =<< inRepo (gitAnnexLocation key)
|
storedirect' [] = storeobject =<< inRepo (gitAnnexLocation key)
|
||||||
storedirect' (dest:fs) = do
|
storedirect' (dest:fs) = do
|
||||||
updateInodeCache key src
|
updateInodeCache key src
|
||||||
thawContent src
|
thawContent src
|
||||||
liftIO $ replaceFile dest $ moveFile src
|
replaceFile dest $ liftIO . moveFile src
|
||||||
liftIO $ forM_ fs $ \f -> replaceFile f $
|
forM_ fs $ \f -> replaceFile f $
|
||||||
void . copyFileExternal dest
|
void . liftIO . copyFileExternal dest
|
||||||
|
|
||||||
{- Replaces any existing file with a new version, by running an action.
|
{- Replaces any existing file with a new version, by running an action.
|
||||||
- First, makes sure the file is deleted. Or, if it didn't already exist,
|
- First, makes sure the file is deleted. Or, if it didn't already exist,
|
||||||
- makes sure the parent directory exists. -}
|
- makes sure the parent directory exists. -}
|
||||||
replaceFile :: FilePath -> (FilePath -> IO ()) -> IO ()
|
replaceFile :: FilePath -> (FilePath -> Annex ()) -> Annex ()
|
||||||
replaceFile file a = do
|
replaceFile file a = do
|
||||||
r <- tryIO $ removeFile file
|
liftIO $ do
|
||||||
case r of
|
r <- tryIO $ removeFile file
|
||||||
Left _ -> createDirectoryIfMissing True (parentDir file)
|
case r of
|
||||||
_ -> noop
|
Left _ -> createDirectoryIfMissing True $ parentDir file
|
||||||
|
_ -> noop
|
||||||
a file
|
a file
|
||||||
|
|
||||||
{- Runs an action to transfer an object's content.
|
{- Runs an action to transfer an object's content.
|
||||||
|
@ -370,8 +365,8 @@ removeAnnex key = withObjectLoc key remove removedirect
|
||||||
cwd <- liftIO getCurrentDirectory
|
cwd <- liftIO getCurrentDirectory
|
||||||
let top' = fromMaybe top $ absNormPath cwd top
|
let top' = fromMaybe top $ absNormPath cwd top
|
||||||
let l' = relPathDirToFile top' (fromMaybe l $ absNormPath top' l)
|
let l' = relPathDirToFile top' (fromMaybe l $ absNormPath top' l)
|
||||||
liftIO $ replaceFile f $ const $
|
replaceFile f $ const $
|
||||||
createSymbolicLink l' f
|
makeAnnexLink l' f
|
||||||
|
|
||||||
{- Moves a key's file out of .git/annex/objects/ -}
|
{- Moves a key's file out of .git/annex/objects/ -}
|
||||||
fromAnnex :: Key -> FilePath -> Annex ()
|
fromAnnex :: Key -> FilePath -> Annex ()
|
||||||
|
|
|
@ -155,8 +155,8 @@ mergeDirectCleanup d oldsha newsha = do
|
||||||
- Symlinks are replaced with their content, if it's available. -}
|
- Symlinks are replaced with their content, if it's available. -}
|
||||||
movein k f = do
|
movein k f = do
|
||||||
l <- calcGitLink f k
|
l <- calcGitLink f k
|
||||||
liftIO $ replaceFile f $ const $
|
replaceFile f $ const $
|
||||||
createSymbolicLink l f
|
liftIO $ createSymbolicLink l f
|
||||||
toDirect k f
|
toDirect k f
|
||||||
|
|
||||||
{- Any new, modified, or renamed files were written to the temp
|
{- Any new, modified, or renamed files were written to the temp
|
||||||
|
@ -181,14 +181,15 @@ toDirectGen k f = do
|
||||||
{- Move content from annex to direct file. -}
|
{- Move content from annex to direct file. -}
|
||||||
updateInodeCache k loc
|
updateInodeCache k loc
|
||||||
thawContent loc
|
thawContent loc
|
||||||
liftIO $ replaceFile f $ moveFile loc
|
replaceFile f $
|
||||||
|
liftIO . moveFile loc
|
||||||
, return Nothing
|
, return Nothing
|
||||||
)
|
)
|
||||||
(loc':_) -> ifM (liftIO $ catchBoolIO $ not . isSymbolicLink <$> getSymbolicLinkStatus loc')
|
(loc':_) -> ifM (liftIO $ catchBoolIO $ not . isSymbolicLink <$> getSymbolicLinkStatus loc')
|
||||||
{- Another direct file has the content; copy it. -}
|
{- Another direct file has the content; copy it. -}
|
||||||
( return $ Just $ do
|
( return $ Just $
|
||||||
liftIO $ replaceFile f $
|
replaceFile f $
|
||||||
void . copyFileExternal loc'
|
void . liftIO . copyFileExternal loc'
|
||||||
, return Nothing
|
, return Nothing
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
47
Backend.hs
47
Backend.hs
|
@ -1,6 +1,6 @@
|
||||||
{- git-annex key/value backends
|
{- git-annex key/value backends
|
||||||
-
|
-
|
||||||
- Copyright 2010 Joey Hess <joey@kitenet.net>
|
- Copyright 2010,2013 Joey Hess <joey@kitenet.net>
|
||||||
-
|
-
|
||||||
- Licensed under the GNU GPL version 3 or higher.
|
- Licensed under the GNU GPL version 3 or higher.
|
||||||
-}
|
-}
|
||||||
|
@ -10,6 +10,8 @@ module Backend (
|
||||||
orderedList,
|
orderedList,
|
||||||
genKey,
|
genKey,
|
||||||
lookupFile,
|
lookupFile,
|
||||||
|
isAnnexLink,
|
||||||
|
makeAnnexLink,
|
||||||
chooseBackend,
|
chooseBackend,
|
||||||
lookupBackendName,
|
lookupBackendName,
|
||||||
maybeLookupBackendName
|
maybeLookupBackendName
|
||||||
|
@ -81,20 +83,20 @@ genKey' (b:bs) source = do
|
||||||
- the symlink is looked up in git instead. However, a real symlink
|
- the symlink is looked up in git instead. However, a real symlink
|
||||||
- on disk still takes precedence over what was committed to git in direct
|
- on disk still takes precedence over what was committed to git in direct
|
||||||
- mode.
|
- mode.
|
||||||
|
-
|
||||||
|
- On a filesystem that does not support symlinks, git will instead store
|
||||||
|
- the symlink target in a regular file.
|
||||||
-}
|
-}
|
||||||
lookupFile :: FilePath -> Annex (Maybe (Key, Backend))
|
lookupFile :: FilePath -> Annex (Maybe (Key, Backend))
|
||||||
lookupFile file = do
|
lookupFile file = do
|
||||||
tl <- liftIO $ tryIO $ readSymbolicLink file
|
mkey <- isAnnexLink file
|
||||||
case tl of
|
case mkey of
|
||||||
Right l
|
Just key -> makeret key
|
||||||
| isLinkToAnnex l -> makekey l
|
Nothing -> ifM isDirect
|
||||||
| otherwise -> return Nothing
|
|
||||||
Left _ -> ifM isDirect
|
|
||||||
( maybe (return Nothing) makeret =<< catKeyFile file
|
( maybe (return Nothing) makeret =<< catKeyFile file
|
||||||
, return Nothing
|
, return Nothing
|
||||||
)
|
)
|
||||||
where
|
where
|
||||||
makekey l = maybe (return Nothing) makeret (fileKey $ takeFileName l)
|
|
||||||
makeret k = let bname = keyBackendName k in
|
makeret k = let bname = keyBackendName k in
|
||||||
case maybeLookupBackendName bname of
|
case maybeLookupBackendName bname of
|
||||||
Just backend -> do
|
Just backend -> do
|
||||||
|
@ -105,6 +107,35 @@ lookupFile file = do
|
||||||
" (unknown backend " ++ bname ++ ")"
|
" (unknown backend " ++ bname ++ ")"
|
||||||
return Nothing
|
return Nothing
|
||||||
|
|
||||||
|
{- Checks if a file is a symlink to a key.
|
||||||
|
-
|
||||||
|
- On a filesystem that does not support symlinks, git will instead store
|
||||||
|
- the symlink target in a regular file. (Only look at first 8k of file,
|
||||||
|
- more than enough for any symlink target.)
|
||||||
|
-}
|
||||||
|
isAnnexLink :: FilePath -> Annex (Maybe Key)
|
||||||
|
isAnnexLink file = maybe Nothing makekey <$> gettarget
|
||||||
|
where
|
||||||
|
gettarget = ifM (coreSymlinks <$> Annex.getGitConfig)
|
||||||
|
( liftIO $ catchMaybeIO $ readSymbolicLink file
|
||||||
|
, liftIO $ catchMaybeIO $ take 8192 <$> readFile file
|
||||||
|
)
|
||||||
|
makekey l
|
||||||
|
| isLinkToAnnex l = fileKey $ takeFileName l
|
||||||
|
| otherwise = Nothing
|
||||||
|
|
||||||
|
{- Creates a symlink on disk.
|
||||||
|
-
|
||||||
|
- On a filesystem that does not support symlinks, writes the link target
|
||||||
|
- to a file. Note that git will only treat the file as a symlink if
|
||||||
|
- it's staged as such.
|
||||||
|
-}
|
||||||
|
makeAnnexLink :: String -> FilePath -> Annex ()
|
||||||
|
makeAnnexLink linktarget file = ifM (coreSymlinks <$> Annex.getGitConfig)
|
||||||
|
( liftIO $ createSymbolicLink linktarget file
|
||||||
|
, liftIO $ writeFile file linktarget
|
||||||
|
)
|
||||||
|
|
||||||
{- Looks up the backend that should be used for a file.
|
{- Looks up the backend that should be used for a file.
|
||||||
- That can be configured on a per-file basis in the gitattributes file. -}
|
- That can be configured on a per-file basis in the gitattributes file. -}
|
||||||
chooseBackend :: FilePath -> Annex (Maybe Backend)
|
chooseBackend :: FilePath -> Annex (Maybe Backend)
|
||||||
|
|
|
@ -36,38 +36,40 @@ data GitConfig = GitConfig
|
||||||
, annexAutoCommit :: Bool
|
, annexAutoCommit :: Bool
|
||||||
, annexWebOptions :: [String]
|
, annexWebOptions :: [String]
|
||||||
, annexCrippledFileSystem :: Bool
|
, annexCrippledFileSystem :: Bool
|
||||||
|
, coreSymlinks :: Bool
|
||||||
}
|
}
|
||||||
|
|
||||||
extractGitConfig :: Git.Repo -> GitConfig
|
extractGitConfig :: Git.Repo -> GitConfig
|
||||||
extractGitConfig r = GitConfig
|
extractGitConfig r = GitConfig
|
||||||
{ annexVersion = notempty $ getmaybe "version"
|
{ annexVersion = notempty $ getmaybe (annex "version")
|
||||||
, annexNumCopies = get "numcopies" 1
|
, annexNumCopies = get (annex "numcopies") 1
|
||||||
, annexDiskReserve = fromMaybe onemegabyte $
|
, annexDiskReserve = fromMaybe onemegabyte $
|
||||||
readSize dataUnits =<< getmaybe "diskreserve"
|
readSize dataUnits =<< getmaybe (annex "diskreserve")
|
||||||
, annexDirect = getbool "direct" False
|
, annexDirect = getbool (annex "direct") False
|
||||||
, annexBackends = getwords "backends"
|
, annexBackends = getwords (annex "backends")
|
||||||
, annexQueueSize = getmayberead "queuesize"
|
, annexQueueSize = getmayberead (annex "queuesize")
|
||||||
, annexBloomCapacity = getmayberead "bloomcapacity"
|
, annexBloomCapacity = getmayberead (annex "bloomcapacity")
|
||||||
, annexBloomAccuracy = getmayberead "bloomaccuracy"
|
, annexBloomAccuracy = getmayberead (annex "bloomaccuracy")
|
||||||
, annexSshCaching = getmaybebool "sshcaching"
|
, annexSshCaching = getmaybebool (annex "sshcaching")
|
||||||
, annexAlwaysCommit = getbool "alwayscommit" True
|
, annexAlwaysCommit = getbool (annex "alwayscommit") True
|
||||||
, annexDelayAdd = getmayberead "delayadd"
|
, annexDelayAdd = getmayberead (annex "delayadd")
|
||||||
, annexHttpHeaders = getlist "http-headers"
|
, annexHttpHeaders = getlist (annex "http-headers")
|
||||||
, annexHttpHeadersCommand = getmaybe "http-headers-command"
|
, annexHttpHeadersCommand = getmaybe (annex "http-headers-command")
|
||||||
, annexAutoCommit = getbool "autocommit" True
|
, annexAutoCommit = getbool (annex "autocommit") True
|
||||||
, annexWebOptions = getwords "web-options"
|
, annexWebOptions = getwords (annex "web-options")
|
||||||
, annexCrippledFileSystem = getbool "crippledfilesystem" False
|
, annexCrippledFileSystem = getbool (annex "crippledfilesystem") False
|
||||||
|
, coreSymlinks = getbool "core.symlinks" True
|
||||||
}
|
}
|
||||||
where
|
where
|
||||||
get k def = fromMaybe def $ getmayberead k
|
get k def = fromMaybe def $ getmayberead k
|
||||||
getbool k def = fromMaybe def $ getmaybebool k
|
getbool k def = fromMaybe def $ getmaybebool k
|
||||||
getmaybebool k = Git.Config.isTrue =<< getmaybe k
|
getmaybebool k = Git.Config.isTrue =<< getmaybe k
|
||||||
getmayberead k = readish =<< getmaybe k
|
getmayberead k = readish =<< getmaybe k
|
||||||
getmaybe k = Git.Config.getMaybe (key k) r
|
getmaybe k = Git.Config.getMaybe k r
|
||||||
getlist k = Git.Config.getList (key k) r
|
getlist k = Git.Config.getList k r
|
||||||
getwords k = fromMaybe [] $ words <$> getmaybe k
|
getwords k = fromMaybe [] $ words <$> getmaybe k
|
||||||
|
|
||||||
key k = "annex." ++ k
|
annex k = "annex." ++ k
|
||||||
|
|
||||||
onemegabyte = 1000000
|
onemegabyte = 1000000
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue