git-annex 7.20190819 → 7.20190912
raw patch · 95 files changed
+1156/−2640 lines, 95 files
Files
- Annex.hs +1/−1
- Annex/AdjustedBranch.hs +3/−13
- Annex/AutoMerge.hs +5/−19
- Annex/CheckIgnore.hs +6/−10
- Annex/Content.hs +68/−182
- Annex/Content/Direct.hs +0/−181
- Annex/Content/LowLevel.hs +5/−6
- Annex/Direct.hs +0/−484
- Annex/Drop.hs +2/−10
- Annex/Fixup.hs +2/−5
- Annex/Ingest.hs +10/−46
- Annex/Init.hs +21/−45
- Annex/Locations.hs +2/−1
- Annex/MakeRepo.hs +0/−90
- Annex/Tmp.hs +20/−6
- Annex/UpdateInstead.hs +4/−8
- Annex/Version.hs +3/−26
- Annex/WorkTree.hs +6/−11
- Assistant/MakeRepo.hs +93/−0
- Assistant/Threads/Committer.hs +21/−80
- Assistant/Threads/SanityChecker.hs +1/−3
- Assistant/Threads/Watcher.hs +15/−50
- Assistant/Upgrade.hs +1/−1
- Assistant/WebApp/Configurators/Local.hs +1/−1
- Build/BundledPrograms.hs +2/−0
- Build/Configure.hs +1/−1
- CHANGELOG +40/−0
- CmdLine/Seek.hs +4/−21
- Command.hs +0/−5
- Command/Add.hs +5/−24
- Command/AddUnused.hs +3/−4
- Command/Adjust.hs +1/−1
- Command/DiffDriver.hs +1/−6
- Command/Direct.hs +2/−48
- Command/EnableTor.hs +4/−0
- Command/Fix.hs +2/−7
- Command/FromKey.hs +1/−1
- Command/Fsck.hs +36/−86
- Command/FuzzTest.hs +0/−8
- Command/Indirect.hs +2/−77
- Command/Info.hs +11/−18
- Command/Lock.hs +2/−8
- Command/Migrate.hs +1/−1
- Command/Multicast.hs +1/−4
- Command/PreCommit.hs +17/−58
- Command/Proxy.hs +2/−58
- Command/ReKey.hs +4/−5
- Command/RegisterUrl.hs +1/−1
- Command/Status.hs +1/−43
- Command/Sync.hs +14/−26
- Command/Unannex.hs +7/−75
- Command/Undo.hs +1/−12
- Command/Uninit.hs +1/−1
- Command/Unlock.hs +8/−52
- Command/Unused.hs +1/−3
- Command/Upgrade.hs +7/−3
- Command/VAdd.hs +1/−1
- Command/VCycle.hs +1/−1
- Command/VFilter.hs +1/−1
- Command/VPop.hs +1/−1
- Command/View.hs +1/−1
- Database/Keys.hs +2/−6
- Git/Branch.hs +1/−3
- Git/CheckAttr.hs +7/−16
- Git/CheckIgnore.hs +2/−14
- Git/Fsck.hs +14/−21
- Git/Index.hs +0/−16
- Git/Merge.hs +1/−2
- Git/Remote/Remove.hs +5/−12
- NEWS +28/−0
- Remote/Git.hs +21/−20
- Test.hs +110/−204
- Test/Framework.hs +11/−34
- Types/GitConfig.hs +2/−0
- Upgrade.hs +19/−7
- Upgrade/V4.hs +3/−11
- Upgrade/V5.hs +87/−56
- Upgrade/V5/Direct.hs +126/−0
- Utility/CopyFile.hs +2/−1
- Utility/DottedVersion.hs +4/−1
- Utility/InodeCache.hs +2/−0
- Utility/Path/Max.hs +0/−2
- doc/git-annex-add.mdwn +2/−3
- doc/git-annex-adjust.mdwn +0/−2
- doc/git-annex-contentlocation.mdwn +0/−4
- doc/git-annex-direct.mdwn +4/−17
- doc/git-annex-examinekey.mdwn +1/−2
- doc/git-annex-indirect.mdwn +5/−5
- doc/git-annex-pre-commit.mdwn +0/−3
- doc/git-annex-proxy.mdwn +4/−31
- doc/git-annex-status.mdwn +0/−2
- doc/git-annex-unlock.mdwn +18/−16
- doc/git-annex-upgrade.mdwn +8/−5
- doc/git-annex.mdwn +186/−179
- git-annex.cabal +3/−4
Annex.hs view
@@ -118,7 +118,7 @@ , catfilehandles :: M.Map FilePath CatFileHandle , hashobjecthandle :: Maybe HashObjectHandle , checkattrhandle :: Maybe CheckAttrHandle- , checkignorehandle :: Maybe (Maybe CheckIgnoreHandle)+ , checkignorehandle :: Maybe CheckIgnoreHandle , forcebackend :: Maybe String , globalnumcopies :: Maybe NumCopies , forcenumcopies :: Maybe NumCopies
Annex/AdjustedBranch.hs view
@@ -26,7 +26,6 @@ propigateAdjustedCommits, AdjustedClone(..), checkAdjustedClone,- isSupported, checkVersionSupported, isGitVersionSupported, ) where@@ -50,7 +49,6 @@ import Git.FilePath import qualified Git.LockFile import qualified Git.Version-import Annex.Version import Annex.CatFile import Annex.Link import Annex.AutoMerge@@ -572,7 +570,7 @@ (Git.DiffTree.dstmode dti) (Git.DiffTree.dstsha dti) -data AdjustedClone = InAdjustedClone | NotInAdjustedClone | NeedUpgradeForAdjustedClone+data AdjustedClone = InAdjustedClone | NotInAdjustedClone {- Cloning a repository that has an adjusted branch checked out will - result in the clone having the same adjusted branch checked out -- but@@ -611,18 +609,10 @@ case aps of Just [p] -> setBasisBranch basis p _ -> giveup $ "Unable to clean up from clone of adjusted branch; perhaps you should check out " ++ Git.Ref.describe origbranch- ifM versionSupportsUnlockedPointers- ( return InAdjustedClone- , return NeedUpgradeForAdjustedClone- )--isSupported :: Annex Bool-isSupported = versionSupportsAdjustedBranch <&&> liftIO isGitVersionSupported+ return InAdjustedClone checkVersionSupported :: Annex ()-checkVersionSupported = do- unlessM versionSupportsAdjustedBranch $- giveup "Adjusted branches are only supported in v6 or newer repositories."+checkVersionSupported = unlessM (liftIO isGitVersionSupported) $ giveup "Your version of git is too old; upgrade it to 2.2.0 or newer to use adjusted branches."
Annex/AutoMerge.hs view
@@ -13,7 +13,6 @@ import Annex.Common import qualified Annex.Queue-import Annex.Direct import Annex.CatFile import Annex.Link import Annex.Content@@ -25,7 +24,6 @@ import qualified Git.Branch import Git.Types (TreeItemType(..), fromTreeItemType) import Git.FilePath-import Config import Annex.ReplaceFile import Annex.VariantFile import qualified Database.Keys@@ -50,9 +48,7 @@ Nothing -> go Nothing Just b -> go =<< inRepo (Git.Ref.sha b) where- go old = ifM isDirect- ( mergeDirect currbranch old branch resolvemerge mergeconfig commitmode- , do+ go old = do r <- inRepo (Git.Merge.merge branch mergeconfig commitmode) <||> (resolvemerge <&&> commitResolvedMerge commitmode) -- Merging can cause new associated files to appear@@ -61,7 +57,6 @@ -- close the database if it was open. Database.Keys.closeDb return r- ) where resolvemerge = ifM canresolvemerge ( resolveMerge old branch False@@ -88,13 +83,9 @@ - the other as a directory or non-annexed file. The annexed file - is renamed to resolve the merge, and the other object is preserved as-is. -- - In indirect mode, the merge is resolved in the work tree and files+ - The merge is resolved in the work tree and files - staged, to clean up from a conflicted merge that was run in the work - tree. - -- - In direct mode, the work tree is not touched here; files are staged to- - the index, and written to the gitAnnexMergeDir, for later handling by- - the direct mode merge code. - - This is complicated by needing to support merges run in an overlay - work tree, in which case the CWD won't be within the work tree.@@ -126,7 +117,7 @@ let merged = not (null mergedfs') void $ liftIO cleanup - unlessM (pure inoverlay <||> isDirect) $ do+ unless inoverlay $ do (deleted, cleanup2) <- inRepo (LsFiles.deleted [top]) unless (null deleted) $ Annex.Queue.addCommand "rm"@@ -136,7 +127,7 @@ when merged $ do Annex.Queue.flush- unlessM (pure inoverlay <||> isDirect) $ do+ unless inoverlay $ do unstagedmap <- inodeMap $ inRepo $ LsFiles.notInRepo False [top] cleanConflictCruft mergedks' mergedfs' unstagedmap showLongNote "Merge conflict was automatically resolved; you may want to examine the result."@@ -230,12 +221,7 @@ Database.Keys.addAssociatedFile key =<< inRepo (toTopFilePath dest) - withworktree f a = ifM isDirect- ( do- d <- fromRepo gitAnnexMergeDir- a (d </> f)- , a f- )+ withworktree f a = a f {- Stage a graft of a directory or file from a branch - and update the work tree. -}
Annex/CheckIgnore.hs view
@@ -19,23 +19,19 @@ checkIgnored :: FilePath -> Annex Bool checkIgnored file = go =<< checkIgnoreHandle where- go Nothing = return False- go (Just h) = liftIO $ Git.checkIgnored h file+ go h = liftIO $ Git.checkIgnored h file -checkIgnoreHandle :: Annex (Maybe Git.CheckIgnoreHandle)+checkIgnoreHandle :: Annex Git.CheckIgnoreHandle checkIgnoreHandle = maybe startup return =<< Annex.getState Annex.checkignorehandle where startup = do- v <- inRepo Git.checkIgnoreStart- when (isNothing v) $- warning "The installed version of git is too old for .gitignores to be honored by git-annex."- Annex.changeState $ \s -> s { Annex.checkignorehandle = Just v }- return v+ h <- inRepo Git.checkIgnoreStart+ Annex.changeState $ \s -> s { Annex.checkignorehandle = Just h }+ return h checkIgnoreStop :: Annex () checkIgnoreStop = maybe noop stop =<< Annex.getState Annex.checkignorehandle where- stop (Just h) = do+ stop h = do liftIO $ Git.checkIgnoreStop h Annex.changeState $ \s -> s { Annex.checkignorehandle = Nothing }- stop Nothing = noop
Annex/Content.hs view
@@ -1,6 +1,6 @@ {- git-annex file content managing -- - Copyright 2010-2018 Joey Hess <id@joeyh.name>+ - Copyright 2010-2019 Joey Hess <id@joeyh.name> - - Licensed under the GNU AGPL version 3 or higher. -}@@ -38,7 +38,7 @@ removeAnnex, moveBad, KeyLocation(..),- getKeysPresent,+ listKeys, saveState, downloadUrl, preseedTmp,@@ -70,12 +70,9 @@ import qualified Annex.Url as Url import Utility.CopyFile import Utility.Metered-import Config import Git.FilePath import Annex.Perms import Annex.Link-import qualified Annex.Content.Direct as Direct-import Annex.ReplaceFile import Annex.LockPool import Messages.Progress import Types.Remote (unVerified, Verification(..), RetrievalSecurityPolicy(..))@@ -103,36 +100,22 @@ {- inAnnex that performs an arbitrary check of the key's content. -} inAnnex' :: (a -> Bool) -> a -> (FilePath -> Annex a) -> Key -> Annex a-inAnnex' isgood bad check key = withObjectLoc key checkindirect checkdirect- where- checkindirect loc = do- r <- check loc- if isgood r- then ifM (annexThin <$> Annex.getGitConfig)- -- When annex.thin is set, the object file- -- could be modified; make sure it's not.- -- (Suppress any messages about- -- checksumming, to avoid them cluttering- -- the display.)- ( ifM (doQuietAction $ isUnmodified key loc)- ( return r- , return bad- )- , return r- )- else return bad- - -- In direct mode, at least one of the associated files must pass the- -- check. Additionally, the file must be unmodified.- checkdirect [] = return bad- checkdirect (loc:locs) = do- r <- check loc- if isgood r- then ifM (Direct.goodContent key loc)+inAnnex' isgood bad check key = withObjectLoc key $ \loc -> do+ r <- check loc+ if isgood r+ then ifM (annexThin <$> Annex.getGitConfig)+ -- When annex.thin is set, the object file+ -- could be modified; make sure it's not.+ -- (Suppress any messages about+ -- checksumming, to avoid them cluttering+ -- the display.)+ ( ifM (doQuietAction $ isUnmodified key loc) ( return r- , checkdirect locs+ , return bad )- else checkdirect locs+ , return r+ )+ else return bad {- Like inAnnex, checks if the object file for a key exists, - but there are no guarantees it has the right content. -}@@ -148,15 +131,13 @@ is_unlocked = Just True is_missing = Just False - go contentfile = maybe (checkindirect contentfile) (checkdirect contentfile)- =<< contentLockFile key+ go contentfile = flip checklock contentfile =<< contentLockFile key #ifndef mingw32_HOST_OS- checkindirect contentfile = checkOr is_missing contentfile- {- In direct mode, the content file must exist, but- - the lock file generally won't exist unless a removal is in- - process. -}- checkdirect contentfile lockfile =+ checklock Nothing contentfile = checkOr is_missing contentfile+ {- The content file must exist, but the lock file generally+ - won't exist unless a removal is in process. -}+ checklock (Just lockfile) contentfile = ifM (liftIO $ doesFileExist contentfile) ( checkOr is_unlocked lockfile , return is_missing@@ -166,8 +147,8 @@ Just True -> is_locked Just False -> is_unlocked #else- checkindirect f = liftIO $ ifM (doesFileExist f)- ( lockShared f >>= \case+ checklock Nothing contentfile = liftIO $ ifM (doesFileExist contentfile)+ ( lockShared contentfile >>= \case Nothing -> return is_locked Just lockhandle -> do dropLock lockhandle@@ -176,7 +157,7 @@ ) {- In Windows, see if we can take a shared lock. If so, - remove the lock file to clean up after ourselves. -}- checkdirect contentfile lockfile =+ checklock (Just lockfile) contentfile = ifM (liftIO $ doesFileExist contentfile) ( modifyContent lockfile $ liftIO $ lockShared lockfile >>= \case@@ -189,15 +170,12 @@ ) #endif -{- Direct mode and especially Windows has to use a separate lock- - file from the content, since locking the actual content file- - would interfere with the user's use of it. -}+{- Windows has to use a separate lock file from the content, since+ - locking the actual content file would interfere with the user's+ - use of it. -} contentLockFile :: Key -> Annex (Maybe FilePath) #ifndef mingw32_HOST_OS-contentLockFile key = ifM isDirect- ( Just <$> calcRepo (gitAnnexContentLock key)- , return Nothing- )+contentLockFile _ = pure Nothing #else contentLockFile key = Just <$> calcRepo (gitAnnexContentLock key) #endif@@ -207,9 +185,6 @@ - - If locking fails, or the content is not present, throws an exception - rather than running the action.- -- - Note that, in direct mode, nothing prevents the user from directly- - editing or removing the content, even while it's locked by this. -} lockContentShared :: Key -> (VerifiedCopy -> Annex a) -> Annex a lockContentShared key a = lockContentUsing lock key $ ifM (inAnnex key)@@ -467,8 +442,6 @@ - - When a key has associated pointer files, the object is hard - linked (or copied) to the files, and the object file is left thawed.- - - - In direct mode, moves the object file to the associated file, or files. - - What if the key there already has content? This could happen for - various reasons; perhaps the same content is being annexed again.@@ -496,7 +469,7 @@ moveAnnex :: Key -> FilePath -> Annex Bool moveAnnex key src = ifM (checkSecureHashes key) ( do- withObjectLoc key storeobject storedirect+ withObjectLoc key storeobject return True , return False )@@ -513,32 +486,6 @@ ics <- mapM (populatePointerFile (Restage True) key dest) fs Database.Keys.storeInodeCaches' key [dest] (catMaybes ics) )- storeindirect = storeobject =<< calcRepo (gitAnnexLocation key)-- {- In direct mode, the associated file's content may be locally- - modified. In that case, it's preserved. However, the content- - we're moving into the annex may be the only extant copy, so- - it's important we not lose it. So, when the key's content- - cannot be moved to any associated file, it's stored in indirect- - mode.- -}- storedirect = storedirect' storeindirect- storedirect' fallback [] = fallback- storedirect' fallback (f:fs) = do- thawContent src- v <- isAnnexLink f- if Just key == v- then do- Direct.updateInodeCache key src- replaceFile f $ liftIO . moveFile src- chmodContent f- forM_ fs $- Direct.addContentWhenNotPresent key f- else ifM (Direct.goodContent key f)- ( storedirect' alreadyhave fs- , storedirect' fallback fs- )- alreadyhave = liftIO $ removeFile src checkSecureHashes :: Key -> Annex Bool@@ -647,8 +594,8 @@ {- Returns a file that contains an object's content, - and a check to run after the transfer is complete. -- - When a file is unlocked (or in direct mode), it's possble for its- - content to change as it's being sent. The check detects this case+ - When a file is unlocked, it's possble for its content to+ - change as it's being sent. The check detects this case - and returns False. - - Note that the returned check action is, in some cases, run in the@@ -656,47 +603,24 @@ - the sender. So it cannot rely on Annex state. -} prepSendAnnex :: Key -> Annex (Maybe (FilePath, Annex Bool))-prepSendAnnex key = withObjectLoc key indirect direct- where- indirect f = do- cache <- Database.Keys.getInodeCaches key- cache' <- if null cache- -- Since no inode cache is in the database, this- -- object is not currently unlocked. But that could- -- change while the transfer is in progress, so- -- generate an inode cache for the starting- -- content.- then maybeToList <$>- withTSDelta (liftIO . genInodeCache f)- else pure cache- return $ if null cache'- then Nothing- else Just (f, sameInodeCache f cache')- direct [] = return Nothing- direct (f:fs) = do- cache <- Direct.recordedInodeCache key- -- check that we have a good file- ifM (sameInodeCache f cache)- ( return $ Just (f, sameInodeCache f cache)- , direct fs- )+prepSendAnnex key = withObjectLoc key $ \f -> do+ cache <- Database.Keys.getInodeCaches key+ cache' <- if null cache+ -- Since no inode cache is in the database, this+ -- object is not currently unlocked. But that could+ -- change while the transfer is in progress, so+ -- generate an inode cache for the starting+ -- content.+ then maybeToList <$>+ withTSDelta (liftIO . genInodeCache f)+ else pure cache+ return $ if null cache'+ then Nothing+ else Just (f, sameInodeCache f cache') -{- Performs an action, passing it the location to use for a key's content.- -- - In direct mode, the associated files will be passed. But, if there are- - no associated files for a key, the indirect mode action will be- - performed instead. -}-withObjectLoc :: Key -> (FilePath -> Annex a) -> ([FilePath] -> Annex a) -> Annex a-withObjectLoc key indirect direct = ifM isDirect- ( do- fs <- Direct.associatedFiles key- if null fs- then goindirect- else direct fs- , goindirect- )- where- goindirect = indirect =<< calcRepo (gitAnnexLocation key)+{- Performs an action, passing it the location to use for a key's content. -}+withObjectLoc :: Key -> (FilePath -> Annex a) -> Annex a+withObjectLoc key a = a =<< calcRepo (gitAnnexLocation key) cleanObjectLoc :: Key -> Annex () -> Annex () cleanObjectLoc key cleaner = do@@ -714,17 +638,15 @@ {- Removes a key's file from .git/annex/objects/ -} removeAnnex :: ContentRemovalLock -> Annex ()-removeAnnex (ContentRemovalLock key) = withObjectLoc key remove removedirect- where- remove file = cleanObjectLoc key $ do+removeAnnex (ContentRemovalLock key) = withObjectLoc key $ \file ->+ cleanObjectLoc key $ do secureErase file liftIO $ nukeFile file g <- Annex.gitRepo mapM_ (\f -> void $ tryIO $ resetpointer $ fromTopFilePath f g) =<< Database.Keys.getAssociatedFiles key Database.Keys.removeInodeCaches key- Direct.removeInodeCache key- + where -- Check associated pointer file for modifications, and reset if -- it's unmodified. resetpointer file = ifM (isUnmodified key file)@@ -736,18 +658,6 @@ , void $ tryIO $ thawContent file ) - -- In direct mode, deletes the associated files or files, and replaces- -- them with symlinks.- removedirect fs = do- cache <- Direct.recordedInodeCache key- Direct.removeInodeCache key- mapM_ (resetfile cache) fs- - resetfile cache f = whenM (Direct.sameInodeCache f cache) $ do- l <- calcRepo $ gitAnnexLink f key- secureErase f- replaceFile f $ makeAnnexLink l- {- Check if a file contains the unmodified content of the key. - - The expensive way to tell is to do a verification of its content.@@ -802,35 +712,32 @@ logStatus key InfoMissing return dest -data KeyLocation = InAnnex | InRepository | InAnywhere+data KeyLocation = InAnnex | InAnywhere -{- List of keys whose content exists in the specified location.- - - InAnnex only lists keys with content in .git/annex/objects,- - while InRepository, in direct mode, also finds keys with content- - in the work tree. InAnywhere lists all keys that have directories- - in .git/annex/objects, whether or not the content is present.- -- - Note that InRepository has to check whether direct mode files- - have goodContent.+{- InAnnex only lists keys with content in .git/annex/objects.+ - InAnywhere lists all keys that have directories in+ - .git/annex/objects, whether or not the content is present. -}-getKeysPresent :: KeyLocation -> Annex [Key]-getKeysPresent keyloc = do- direct <- isDirect+listKeys :: KeyLocation -> Annex [Key]+listKeys keyloc = do dir <- fromRepo gitAnnexObjectDir- s <- getstate direct+ {- In order to run Annex monad actions within unsafeInterleaveIO,+ - the current state is taken and reused. No changes made to this+ - state will be preserved. + -}+ s <- Annex.getState id depth <- gitAnnexLocationDepth <$> Annex.getGitConfig- liftIO $ walk s direct depth dir+ liftIO $ walk s depth dir where- walk s direct depth dir = do+ walk s depth dir = do contents <- catchDefaultIO [] (dirContents dir) if depth < 2 then do- contents' <- filterM (present s direct) contents+ contents' <- filterM (present s) contents let keys = mapMaybe (fileKey . takeFileName) contents' continue keys [] else do- let deeper = walk s direct (depth - 1)+ let deeper = walk s (depth - 1) continue [] (map deeper contents) continue keys [] = return keys continue keys (a:as) = do@@ -842,32 +749,11 @@ InAnywhere -> True _ -> False - present _ _ _ | inanywhere = pure True- present _ False d = presentInAnnex d- present s True d = presentDirect s d <||> presentInAnnex d+ present _ _ | inanywhere = pure True+ present _ d = presentInAnnex d presentInAnnex = doesFileExist . contentfile contentfile d = d </> takeFileName d-- presentDirect s d = case keyloc of- InAnnex -> return False- InRepository -> case fileKey (takeFileName d) of- Nothing -> return False- Just k -> Annex.eval s $ - anyM (Direct.goodContent k) =<< Direct.associatedFiles k- InAnywhere -> return True-- {- In order to run Annex monad actions within unsafeInterleaveIO,- - the current state is taken and reused. No changes made to this- - state will be preserved. - -- - As an optimsation, call inodesChanged to prime the state with- - a cached value that will be used in the call to goodContent.- -}- getstate direct = do- when direct $- void inodesChanged- Annex.getState id {- Things to do to record changes to content when shutting down. -
− Annex/Content/Direct.hs
@@ -1,181 +0,0 @@-{- git-annex file content managing for direct mode- -- - This is deprecated, and will be removed when direct mode gets removed- - from git-annex.- -- - Copyright 2012-2014 Joey Hess <id@joeyh.name>- -- - Licensed under the GNU AGPL version 3 or higher.- -}--module Annex.Content.Direct (- associatedFiles,- associatedFilesRelative,- removeAssociatedFile,- removeAssociatedFileUnchecked,- removeAssociatedFiles,- addAssociatedFile,- goodContent,- recordedInodeCache,- updateInodeCache,- addInodeCache,- writeInodeCache,- compareInodeCaches,- sameInodeCache,- elemInodeCaches,- sameFileStatus,- removeInodeCache,- toInodeCache,- addContentWhenNotPresent,-) where--import Annex.Common-import Annex.Perms-import qualified Git-import Logs.Location-import Logs.File-import Utility.InodeCache-import Utility.CopyFile-import Annex.ReplaceFile-import Annex.Link-import Annex.InodeSentinal--{- Absolute FilePaths of Files in the tree that are associated with a key. -}-associatedFiles :: Key -> Annex [FilePath]-associatedFiles key = do- files <- associatedFilesRelative key- top <- fromRepo Git.repoPath- return $ map (top </>) files--{- List of files in the tree that are associated with a key, relative to- - the top of the repo. -}-associatedFilesRelative :: Key -> Annex [FilePath] -associatedFilesRelative key = do- mapping <- calcRepo $ gitAnnexMapping key- liftIO $ catchDefaultIO [] $ withFile mapping ReadMode $ \h ->- -- Read strictly to ensure the file is closed- -- before changeAssociatedFiles tries to write to it.- -- (Especially needed on Windows.)- lines <$> hGetContentsStrict h--{- Changes the associated files information for a key, applying a- - transformation to the list. Returns new associatedFiles value. -}-changeAssociatedFiles :: Key -> ([FilePath] -> [FilePath]) -> Annex [FilePath]-changeAssociatedFiles key transform = do- mapping <- calcRepo $ gitAnnexMapping key- files <- associatedFilesRelative key- let files' = transform files- when (files /= files') $- modifyContent mapping $- writeLogFile mapping $ unlines files'- top <- fromRepo Git.repoPath- return $ map (top </>) files'--{- Removes the list of associated files. -}-removeAssociatedFiles :: Key -> Annex ()-removeAssociatedFiles key = do- mapping <- calcRepo $ gitAnnexMapping key- modifyContent mapping $- liftIO $ nukeFile mapping--{- Removes an associated file. Returns new associatedFiles value.- - Checks if this was the last copy of the object, and updates location- - log. -}-removeAssociatedFile :: Key -> FilePath -> Annex [FilePath]-removeAssociatedFile key file = do- fs <- removeAssociatedFileUnchecked key file- when (null fs) $- logStatus key InfoMissing- return fs--{- Removes an associated file. Returns new associatedFiles value. -}-removeAssociatedFileUnchecked :: Key -> FilePath -> Annex [FilePath]-removeAssociatedFileUnchecked key file = do- file' <- normaliseAssociatedFile file- changeAssociatedFiles key $ filter (/= file')--{- Adds an associated file. Returns new associatedFiles value. -}-addAssociatedFile :: Key -> FilePath -> Annex [FilePath]-addAssociatedFile key file = do- file' <- normaliseAssociatedFile file- changeAssociatedFiles key $ \files ->- if file' `elem` files- then files- else file':files--{- Associated files are always stored relative to the top of the repository.- - The input FilePath is relative to the CWD, or is absolute. -}-normaliseAssociatedFile :: FilePath -> Annex FilePath-normaliseAssociatedFile file = do- top <- fromRepo Git.repoPath- liftIO $ relPathDirToFile top file--{- 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- - expensive checksum, this relies on a cache that contains the file's- - expected mtime and inode.- -}-goodContent :: Key -> FilePath -> Annex Bool-goodContent key file = sameInodeCache file =<< recordedInodeCache key--{- Gets the recorded inode cache for a key. - -- - A key can be associated with multiple files, so may return more than- - one. -}-recordedInodeCache :: Key -> Annex [InodeCache]-recordedInodeCache key = withInodeCacheFile key $ \f ->- liftIO $ catchDefaultIO [] $- mapMaybe readInodeCache . lines <$> readFileStrict f--{- Caches an inode for a file.- -- - Anything else already cached is preserved.- -}-updateInodeCache :: Key -> FilePath -> Annex ()-updateInodeCache key file = maybe noop (addInodeCache key)- =<< withTSDelta (liftIO . genInodeCache file)--{- Adds another inode to the cache for a key. -}-addInodeCache :: Key -> InodeCache -> Annex ()-addInodeCache key cache = do- oldcaches <- recordedInodeCache key- unlessM (elemInodeCaches cache oldcaches) $- writeInodeCache key (cache:oldcaches)--{- Writes inode cache for a key. -}-writeInodeCache :: Key -> [InodeCache] -> Annex ()-writeInodeCache key caches = withInodeCacheFile key $ \f -> - modifyContent f $- liftIO $ writeFile f $- unlines $ map showInodeCache caches--{- Removes an inode cache. -}-removeInodeCache :: Key -> Annex ()-removeInodeCache key = withInodeCacheFile key $ \f ->- modifyContent f $- liftIO $ nukeFile f--withInodeCacheFile :: Key -> (FilePath -> Annex a) -> Annex a-withInodeCacheFile key a = a =<< calcRepo (gitAnnexInodeCache key)--{- Checks if a FileStatus matches the recorded InodeCache of a file. -}-sameFileStatus :: Key -> FilePath -> FileStatus -> Annex Bool-sameFileStatus key f status = do- old <- recordedInodeCache key- curr <- withTSDelta $ \delta -> liftIO $ toInodeCache delta f status- case (old, curr) of- (_, Just c) -> elemInodeCaches c old- ([], Nothing) -> return True- _ -> return False--{- Copies the contentfile to the associated file, if the associated- - file has no content. If the associated file does have content,- - even if the content differs, it's left unchanged. -}-addContentWhenNotPresent :: Key -> FilePath -> FilePath -> Annex ()-addContentWhenNotPresent key contentfile associatedfile = do- v <- isAnnexLink associatedfile- when (Just key == v) $- replaceFile associatedfile $- liftIO . void . copyFileExternal CopyAllMetaData contentfile- updateInodeCache key associatedfile
Annex/Content/LowLevel.hs view
@@ -48,12 +48,11 @@ linkOrCopy = linkOrCopy' (annexThin <$> Annex.getGitConfig) linkOrCopy' :: Annex Bool -> Key -> FilePath -> FilePath -> Maybe FileMode -> Annex (Maybe LinkedOrCopied)-linkOrCopy' canhardlink key src dest destmode- | otherwise = catchDefaultIO Nothing $- ifM canhardlink- ( hardlink- , copy =<< getstat- )+linkOrCopy' canhardlink key src dest destmode = catchDefaultIO Nothing $+ ifM canhardlink+ ( hardlink+ , copy =<< getstat+ ) where hardlink = do s <- getstat
− Annex/Direct.hs
@@ -1,484 +0,0 @@-{- git-annex direct mode- -- - This is deprecated, and will be removed when direct mode gets removed- - from git-annex.- -- - Copyright 2012-2014 Joey Hess <id@joeyh.name>- -- - Licensed under the GNU AGPL version 3 or higher.- -}--module Annex.Direct where--import Annex.Common-import qualified Annex-import qualified Git-import qualified Git.LsFiles-import qualified Git.Merge-import qualified Git.DiffTree as DiffTree-import qualified Git.Config-import qualified Git.Ref-import qualified Git.Branch-import Git.Sha-import Git.FilePath-import Git.Types-import Config-import Annex.CatFile-import qualified Annex.Queue-import Logs.Location-import Backend-import Types.KeySource-import Annex.Content-import Annex.Content.Direct-import Annex.Link-import Utility.InodeCache-import Utility.CopyFile-import Annex.Perms-import Annex.ReplaceFile-import Annex.VariantFile-import Git.Index-import Annex.GitOverlay-import Annex.LockFile-import Annex.InodeSentinal-import Utility.Metered--{- Uses git ls-files to find files that need to be committed, and stages- - them into the index. Returns True if some changes were staged. -}-stageDirect :: Annex Bool-stageDirect = do- Annex.Queue.flush- top <- fromRepo Git.repoPath- (l, cleanup) <- inRepo $ Git.LsFiles.stagedOthersDetails [top]- forM_ l go- void $ liftIO cleanup- staged <- Annex.Queue.size- Annex.Queue.flush- return $ staged /= 0- where- {- Determine what kind of modified or deleted file this is, as- - efficiently as we can, by getting any key that's associated- - with it in git, as well as its stat info. -}- go (file, Just sha, Just _mode) = withTSDelta $ \delta -> do- shakey <- catKey sha- mstat <- liftIO $ catchMaybeIO $ getSymbolicLinkStatus file- mcache <- liftIO $ maybe (pure Nothing) (toInodeCache delta file) mstat- filekey <- isAnnexLink file >>= \case- Just k -> return (Just k)- -- v7 unlocked pointer file- Nothing -> liftIO (isPointerFile file)- case (shakey, filekey, mstat, mcache) of- (_, Just key, _, _)- | shakey == filekey -> noop- {- A changed symlink. -}- | otherwise -> stageannexlink file key- (Just key, _, _, Just cache) -> do- {- All direct mode files will show as- - modified, so compare the cache to see if- - it really was. -}- oldcache <- recordedInodeCache key- case oldcache of- [] -> modifiedannexed file key cache- _ -> unlessM (elemInodeCaches cache oldcache) $- modifiedannexed file key cache- (Just key, _, Nothing, _) -> deletedannexed file key- (Nothing, _, Nothing, _) -> deletegit file- (_, _, Just _, _) -> addgit file- go _ = noop-- modifiedannexed file oldkey cache = do- void $ removeAssociatedFile oldkey file- void $ addDirect file cache- - deletedannexed file key = do- void $ removeAssociatedFile key file- deletegit file- - stageannexlink file key = do- l <- calcRepo $ gitAnnexLink file key- stageSymlink file =<< hashSymlink l- void $ addAssociatedFile key file-- addgit file = Annex.Queue.addCommand "add" [Param "-f"] [file]-- deletegit file = Annex.Queue.addCommand "rm" [Param "-qf"] [file]--{- Run before a commit to update direct mode bookeeping to reflect the- - staged changes being committed. -}-preCommitDirect :: Annex Bool-preCommitDirect = do- (diffs, clean) <- inRepo $ DiffTree.diffIndex Git.Ref.headRef- makeabs <- flip fromTopFilePath <$> gitRepo- forM_ diffs (go makeabs)- liftIO clean- where- go makeabs diff = do- withkey (DiffTree.srcsha diff) (DiffTree.srcmode diff) removeAssociatedFile- withkey (DiffTree.dstsha diff) (DiffTree.dstmode diff) addAssociatedFile- where- withkey sha _mode a = when (sha /= nullSha) $- catKey sha >>= \case- Nothing -> noop- Just key -> void $ a key $- makeabs $ DiffTree.file diff--{- Adds a file to the annex in direct mode. Can fail, if the file is- - modified or deleted while it's being added. -}-addDirect :: FilePath -> InodeCache -> Annex Bool-addDirect file cache = do- showStart "add" file- let source = KeySource- { keyFilename = file- , contentLocation = file- , inodeCache = Just cache- }- got =<< genKey source nullMeterUpdate=<< chooseBackend file- where- got Nothing = do- showEndFail- return False- got (Just (key, _)) = ifM (sameInodeCache file [cache])- ( do- l <- calcRepo $ gitAnnexLink file key- stageSymlink file =<< hashSymlink l- addInodeCache key cache- void $ addAssociatedFile key file- logStatus key InfoPresent- showEndOk- return True- , do- showEndFail- return False- )--{- In direct mode, git merge would usually refuse to do anything, since it- - sees present direct mode files as type changed files.- -- - So, to handle a merge, it's run with the work tree set to a temp- - directory, and the merge is staged into a copy of the index.- - Then the work tree is updated to reflect the merge, and- - finally, the merge is committed and the real index updated.- -- - A lock file is used to avoid races with any other caller of mergeDirect.- - - - To avoid other git processes from making changes to the index while our- - merge is in progress, the index lock file is used as the temp index- - file. This is the same as what git does when updating the index- - normally.- -}-mergeDirect :: Maybe Git.Ref -> Maybe Git.Ref -> Git.Branch -> Annex Bool -> [Git.Merge.MergeConfig] -> Git.Branch.CommitMode -> Annex Bool-mergeDirect startbranch oldref branch resolvemerge mergeconfig commitmode = exclusively $ do- reali <- liftIO . absPath =<< fromRepo indexFile- tmpi <- liftIO . absPath =<< fromRepo (indexFileLock . indexFile)- liftIO $ whenM (doesFileExist reali) $- copyFile reali tmpi-- d <- fromRepo gitAnnexMergeDir- liftIO $ do- whenM (doesDirectoryExist d) $- removeDirectoryRecursive d- createDirectoryIfMissing True d-- withIndexFile tmpi $ do- merged <- stageMerge d branch mergeconfig commitmode- ok <- if merged- then return True- else resolvemerge- if ok- then do- mergeDirectCleanup d (fromMaybe Git.Sha.emptyTree oldref)- mergeDirectCommit merged startbranch branch commitmode- liftIO $ whenM (doesFileExist tmpi) $- rename tmpi reali- else do- liftIO $ nukeFile tmpi- liftIO $ removeDirectoryRecursive d- return ok- where- exclusively = withExclusiveLock gitAnnexMergeLock--{- Stage a merge into the index, avoiding changing HEAD or the current- - branch. -}-stageMerge :: FilePath -> Git.Branch -> [Git.Merge.MergeConfig] -> Git.Branch.CommitMode -> Annex Bool-stageMerge d branch mergeconfig commitmode = do- -- XXX A bug in git makes stageMerge unsafe to use if the git repo- -- is configured with core.symlinks=false- -- Using merge is not ideal though, since it will- -- update the current branch immediately, before the work tree- -- has been updated, which would leave things in an inconsistent- -- state if mergeDirectCleanup is interrupted.- -- <http://marc.info/?l=git&m=140262402204212&w=2>- merger <- ifM (coreSymlinks <$> Annex.getGitConfig)- ( return $ \ref -> Git.Merge.stageMerge ref mergeconfig- , return $ \ref -> Git.Merge.merge ref mergeconfig commitmode- )- inRepo $ \g -> do- wd <- liftIO $ absPath d- gd <- liftIO $ absPath $ Git.localGitDir g- merger branch $ - g { location = Local { gitdir = gd, worktree = Just (addTrailingPathSeparator wd) } }--{- Commits after a direct mode merge is complete, and after the work- - tree has been updated by mergeDirectCleanup.- -}-mergeDirectCommit :: Bool -> Maybe Git.Ref -> Git.Branch -> Git.Branch.CommitMode -> Annex ()-mergeDirectCommit allowff old branch commitmode = do- void preCommitDirect- d <- fromRepo Git.localGitDir- let merge_head = d </> "MERGE_HEAD"- let merge_msg = d </> "MERGE_MSG"- let merge_mode = d </> "MERGE_MODE"- ifM (pure allowff <&&> canff)- ( inRepo $ Git.Branch.update "merge" Git.Ref.headRef branch -- fast forward- , do- msg <- liftIO $- catchDefaultIO ("merge " ++ fromRef branch) $- readFile merge_msg- void $ inRepo $ Git.Branch.commit commitmode False msg- Git.Ref.headRef [Git.Ref.headRef, branch]- )- liftIO $ mapM_ nukeFile [merge_head, merge_msg, merge_mode]- where- canff = maybe (return False) (\o -> inRepo $ Git.Branch.fastForwardable o branch) old--mergeDirectCleanup :: FilePath -> Git.Ref -> Annex ()-mergeDirectCleanup d oldref = updateWorkTree d oldref False--{- Updates the direct mode work tree to reflect the changes staged in the- - index by a git command, that was run in a temporary work tree.- -- - Uses diff-index to compare the staged changes with provided ref- - which should be the tree before the merge, and applies those- - changes to the work tree.- -- - There are really only two types of changes: An old item can be deleted,- - or a new item added. Two passes are made, first deleting and then- - adding. This is to handle cases where eg, a file is deleted and a- - directory is added. (The diff-tree output may list these in the opposite- - order, but we cannot add the directory until the file with the- - same name is removed.)- -}-updateWorkTree :: FilePath -> Git.Ref -> Bool -> Annex ()-updateWorkTree d oldref force = do- (items, cleanup) <- inRepo $ DiffTree.diffIndex oldref- makeabs <- flip fromTopFilePath <$> gitRepo- let fsitems = zip (map (makeabs . DiffTree.file) items) items- forM_ fsitems $- go makeabs DiffTree.srcsha moveout moveout_raw- forM_ fsitems $- go makeabs DiffTree.dstsha movein movein_raw- void $ liftIO cleanup- where- go makeabs getsha a araw (f, item)- | getsha item == nullSha = noop- | otherwise = void $- tryNonAsync . maybe (araw item makeabs f) (\k -> void $ a item makeabs k f)- =<< catKey (getsha item)-- moveout _ _ = removeDirect-- {- Files deleted by the merge are removed from the work tree.- - Empty work tree directories are removed, per git behavior. -}- moveout_raw _ _ f = liftIO $ do- nukeFile f- void $ tryIO $ removeDirectory $ parentDir f- - {- If the file is already present, with the right content for the- - key, it's left alone. - -- - If the file is already present, and does not exist in the- - oldref, preserve this local file.- -- - Otherwise, create the symlink and then if possible, replace it- - with the content. -}- movein item makeabs k f = unlessM (goodContent k f) $ do- unless force $ preserveUnannexed item makeabs f oldref- l <- calcRepo $ gitAnnexLink f k- replaceFile f $ makeAnnexLink l- toDirect k f- - {- Any new, modified, or renamed files were written to the temp- - directory by the merge, and are moved to the real work tree. -}- movein_raw item makeabs f = do- unless force $ preserveUnannexed item makeabs f oldref- liftIO $ do- createDirectoryIfMissing True $ parentDir f- void $ tryIO $ rename (d </> getTopFilePath (DiffTree.file item)) f--{- If the file that's being moved in is already present in the work- - tree, but did not exist in the oldref, preserve this- - local, unannexed file (or directory), as "variant-local".- -- - It's also possible that the file that's being moved in- - is in a directory that collides with an exsting, non-annexed- - file (not a directory), which should be preserved.- -}-preserveUnannexed :: DiffTree.DiffTreeItem -> (TopFilePath -> FilePath) -> FilePath -> Ref -> Annex ()-preserveUnannexed item makeabs absf oldref = do- whenM (liftIO (collidingitem absf) <&&> unannexed absf) $- liftIO $ findnewname absf 0- checkdirs (DiffTree.file item)- where- checkdirs from = case upFrom (getTopFilePath from) of- Nothing -> noop- Just p -> do- let d = asTopFilePath p- let absd = makeabs d- whenM (liftIO (colliding_nondir absd) <&&> unannexed absd) $- liftIO $ findnewname absd 0- checkdirs d- - collidingitem f = isJust- <$> catchMaybeIO (getSymbolicLinkStatus f)- colliding_nondir f = maybe False (not . isDirectory)- <$> catchMaybeIO (getSymbolicLinkStatus f)-- unannexed f = (isNothing <$> isAnnexLink f)- <&&> (isNothing <$> catFileDetails oldref f)-- findnewname :: FilePath -> Int -> IO ()- findnewname f n = do- let localf = mkVariant f - ("local" ++ if n > 0 then show n else "")- ifM (collidingitem localf)- ( findnewname f (n+1)- , rename f localf- `catchIO` const (findnewname f (n+1))- )--{- If possible, converts a symlink in the working tree into a direct- - mode file. If the content is not available, leaves the symlink- - unchanged. -}-toDirect :: Key -> FilePath -> Annex ()-toDirect k f = fromMaybe noop =<< toDirectGen k f--toDirectGen :: Key -> FilePath -> Annex (Maybe (Annex ()))-toDirectGen k f = do- loc <- calcRepo $ gitAnnexLocation k- ifM (liftIO $ doesFileExist loc)- ( return $ Just $ fromindirect loc- , do- {- Copy content from another direct file. -}- absf <- liftIO $ absPath f- dlocs <- filterM (goodContent k) =<<- filterM (\l -> isNothing <$> getAnnexLinkTarget l) =<<- (filter (/= absf) <$> addAssociatedFile k f)- case dlocs of- [] -> return Nothing- (dloc:_) -> return $ Just $ fromdirect dloc- )- where- fromindirect loc = do- {- Move content from annex to direct file. -}- updateInodeCache k loc- void $ addAssociatedFile k f- modifyContent loc $ do- thawContent loc- liftIO (replaceFileFrom loc f)- `catchIO` (\_ -> freezeContent loc)- fromdirect loc = do- replaceFile f $- liftIO . void . copyFileExternal CopyAllMetaData loc- updateInodeCache k f--{- Removes a direct mode file, while retaining its content in the annex- - (unless its content has already been changed). -}-removeDirect :: Key -> FilePath -> Annex ()-removeDirect k f = do- void $ removeAssociatedFileUnchecked k f- unlessM (inAnnex k) $- -- If moveAnnex rejects the content of the key,- -- treat that the same as its content having changed.- ifM (goodContent k f)- ( unlessM (moveAnnex k f) $- logStatus k InfoMissing- , logStatus k InfoMissing- )- liftIO $ do- nukeFile f- void $ tryIO $ removeDirectory $ parentDir f--{- Called when a direct mode file has been changed. Its old content may be- - lost. -}-changedDirect :: Key -> FilePath -> Annex ()-changedDirect oldk f = do- locs <- removeAssociatedFile oldk f- whenM (pure (null locs) <&&> not <$> inAnnex oldk) $- logStatus oldk InfoMissing--{- Git config settings to enable/disable direct mode. -}-setDirect :: Bool -> Annex ()-setDirect wantdirect = do- if wantdirect- then do- switchHEAD- setbare- else do- setbare- switchHEADBack- setConfig (annexConfig "direct") val- Annex.changeGitConfig $ \c -> c { annexDirect = wantdirect }- where- val = Git.Config.boolConfig wantdirect- coreworktree = ConfigKey "core.worktree"- indirectworktree = ConfigKey "core.indirect-worktree"- setbare = do- -- core.worktree is not compatable with- -- core.bare; git does not allow both to be set, so- -- unset it when enabling direct mode, caching in- -- core.indirect-worktree- if wantdirect- then moveconfig coreworktree indirectworktree- else moveconfig indirectworktree coreworktree- setConfig (ConfigKey Git.Config.coreBare) val- moveconfig src dest = getConfigMaybe src >>= \case- Nothing -> noop- Just wt -> do- unsetConfig src- setConfig dest wt- reloadConfig--{- Since direct mode sets core.bare=true, incoming pushes could change- - the currently checked out branch. To avoid this problem, HEAD- - is changed to a internal ref that nothing is going to push to.- -- - For refs/heads/master, use refs/heads/annex/direct/master;- - this way things that show HEAD (eg shell prompts) will- - hopefully show just "master". -}-directBranch :: Ref -> Ref-directBranch orighead = case splitc '/' $ fromRef orighead of- ("refs":"heads":"annex":"direct":_) -> orighead- ("refs":"heads":rest) ->- Ref $ "refs/heads/annex/direct/" ++ intercalate "/" rest- _ -> Ref $ "refs/heads/" ++ fromRef (Git.Ref.base orighead)--{- Converts a directBranch back to the original branch.- -- - Any other ref is left unchanged.- -}-fromDirectBranch :: Ref -> Ref-fromDirectBranch directhead = case splitc '/' $ fromRef directhead of- ("refs":"heads":"annex":"direct":rest) -> - Ref $ "refs/heads/" ++ intercalate "/" rest- _ -> directhead--switchHEAD :: Annex ()-switchHEAD = maybe noop switch =<< inRepo Git.Branch.currentUnsafe- where- switch orighead = do- let newhead = directBranch orighead- maybe noop (inRepo . Git.Branch.update "entering direct mode" newhead)- =<< inRepo (Git.Ref.sha orighead)- inRepo $ Git.Branch.checkout newhead--switchHEADBack :: Annex ()-switchHEADBack = maybe noop switch =<< inRepo Git.Branch.currentUnsafe- where- switch currhead = do- let orighead = fromDirectBranch currhead- inRepo (Git.Ref.sha currhead) >>= \case- Just headsha- | orighead /= currhead -> do- inRepo $ Git.Branch.update "leaving direct mode" orighead headsha- inRepo $ Git.Branch.checkout orighead- inRepo $ Git.Branch.delete currhead- _ -> inRepo $ Git.Branch.checkout orighead
Annex/Drop.hs view
@@ -17,7 +17,6 @@ import Command import Annex.Wanted import Config-import Annex.Content.Direct import qualified Database.Keys import Git.FilePath @@ -44,20 +43,13 @@ - A VerifiedCopy can be provided as an optimisation when eg, a key - has just been uploaded to a remote. -- - In direct mode, all associated files are checked, and only if all- - of them are unwanted are they dropped.- - - The runner is used to run CommandStart sequentially, it's typically - callCommandAction. -} handleDropsFrom :: [UUID] -> [Remote] -> Reason -> Bool -> Key -> AssociatedFile -> [VerifiedCopy] -> (CommandStart -> CommandCleanup) -> Annex () handleDropsFrom locs rs reason fromhere key afile preverified runner = do- l <- ifM isDirect- ( associatedFilesRelative key- , do- g <- Annex.gitRepo- map (`fromTopFilePath` g) <$> Database.Keys.getAssociatedFiles key- )+ g <- Annex.gitRepo+ l <- map (`fromTopFilePath` g) <$> Database.Keys.getAssociatedFiles key let fs = case afile of AssociatedFile (Just f) -> nub (f : l) AssociatedFile Nothing -> l
Annex/Fixup.hs view
@@ -12,7 +12,6 @@ import Types.GitConfig import Config.Files import qualified Git-import qualified Git.BuildVersion import Utility.Path import Utility.SafeCommand import Utility.Directory@@ -42,10 +41,8 @@ {- Disable git's built-in wildcard expansion, which is not wanted - when using it as plumbing by git-annex. -} disableWildcardExpansion :: Repo -> Repo-disableWildcardExpansion r- | Git.BuildVersion.older "1.8.1" = r- | otherwise = r- { gitGlobalOpts = gitGlobalOpts r ++ [Param "--literal-pathspecs"] }+disableWildcardExpansion r = r+ { gitGlobalOpts = gitGlobalOpts r ++ [Param "--literal-pathspecs"] } {- Direct mode repos have core.bare=true, but are not really bare. - Fix up the Repo to be a non-bare repo, and arrange for git commands
Annex/Ingest.hs view
@@ -13,7 +13,6 @@ ingestAdd', ingest, ingest',- finishIngestDirect, finishIngestUnlocked, cleanOldKeys, addLink,@@ -28,12 +27,10 @@ import Types.KeySource import Backend import Annex.Content-import Annex.Content.Direct import Annex.Perms import Annex.Link import Annex.MetaData import Annex.CurrentBranch-import Annex.Version import Logs.Location import qualified Annex import qualified Annex.Queue@@ -137,14 +134,9 @@ let f = keyFilename source if lockingFile cfg then addLink f k mic- else ifM isDirect- ( do- l <- calcRepo $ gitAnnexLink f k- stageSymlink f =<< hashSymlink l- , do- mode <- liftIO $ catchMaybeIO $ fileMode <$> getFileStatus (contentLocation source)- stagePointerFile f mode =<< hashPointerFile k- )+ else do+ mode <- liftIO $ catchMaybeIO $ fileMode <$> getFileStatus (contentLocation source)+ stagePointerFile f mode =<< hashPointerFile k return (Just k) {- Ingests a locked down file into the annex. Does not update the working@@ -170,10 +162,7 @@ where go (Just key) mcache (Just s) | lockingFile cfg = golocked key mcache s- | otherwise = ifM isDirect- ( godirect key mcache s- , gounlocked key mcache s- )+ | otherwise = gounlocked key mcache s go _ _ _ = failure "failed to generate a key" golocked key mcache s =@@ -197,12 +186,6 @@ success key (Just cache) s gounlocked _ _ _ = failure "failed statting file" - godirect key (Just cache) s = do- addInodeCache key cache- finishIngestDirect key source- success key (Just cache) s- godirect _ _ _ = failure "failed statting file"- success k mcache s = do genMetaData k (keyFilename source) s return (Just k, mcache)@@ -212,16 +195,6 @@ cleanCruft source return (Nothing, Nothing) -finishIngestDirect :: Key -> KeySource -> Annex ()-finishIngestDirect key source = do- void $ addAssociatedFile key $ keyFilename source- cleanCruft source-- {- Copy to any other locations using the same key. -}- otherfs <- filter (/= keyFilename source) <$> associatedFiles key- forM_ otherfs $- addContentWhenNotPresent key (keyFilename source)- finishIngestUnlocked :: Key -> KeySource -> Annex () finishIngestUnlocked key source = do cleanCruft source@@ -333,12 +306,10 @@ - Also, when in an adjusted unlocked branch, always add files unlocked. -} addUnlocked :: Annex Bool-addUnlocked = isDirect <||>- (versionSupportsUnlockedPointers <&&>- ((not . coreSymlinks <$> Annex.getGitConfig) <||>- (annexAddUnlocked <$> Annex.getGitConfig) <||>- (maybe False isadjustedunlocked . snd <$> getCurrentBranch)- )+addUnlocked =+ ((not . coreSymlinks <$> Annex.getGitConfig) <||>+ (annexAddUnlocked <$> Annex.getGitConfig) <||>+ (maybe False isadjustedunlocked . snd <$> getCurrentBranch) ) where isadjustedunlocked (LinkAdjustment UnlockAdjustment) = True@@ -352,7 +323,7 @@ - When the content of the key is not accepted into the annex, returns False. -} addAnnexedFile :: FilePath -> Key -> Maybe FilePath -> Annex Bool-addAnnexedFile file key mtmp = ifM (addUnlocked <&&> not <$> isDirect)+addAnnexedFile file key mtmp = ifM addUnlocked ( do mode <- maybe (pure Nothing)@@ -371,15 +342,8 @@ ) , do addLink file key Nothing- whenM isDirect $ do- void $ addAssociatedFile key file case mtmp of- Just tmp -> do- {- For moveAnnex to work in direct mode, the- - symlink must already exist, so flush the queue. -}- whenM isDirect $- Annex.Queue.flush- moveAnnex key tmp+ Just tmp -> moveAnnex key tmp Nothing -> return True ) where
Annex/Init.hs view
@@ -22,7 +22,6 @@ import qualified Git import qualified Git.Config import qualified Git.Objects-import qualified Git.LsFiles import qualified Annex.Branch import Logs.UUID import Logs.Trust.Basic@@ -32,12 +31,11 @@ import Annex.Version import Annex.Difference import Annex.UUID-import Annex.Link import Annex.WorkTree import Config import Config.Files import Config.Smudge-import Annex.Direct+import qualified Upgrade.V5.Direct as Direct import qualified Annex.AdjustedBranch as AdjustedBranch import Annex.Environment import Annex.Hook@@ -50,6 +48,7 @@ import Utility.FileMode import System.Posix.User import qualified Utility.LockFile.Posix as Posix+import Data.Either #endif import qualified Data.Map as M@@ -107,27 +106,22 @@ hookWrite postReceiveHook setDifferences unlessM (isJust <$> getVersion) $- ifM (crippledFileSystem <&&> (not <$> isBareRepo))- ( setVersion (fromMaybe versionForCrippledFilesystem mversion)- , setVersion (fromMaybe defaultVersion mversion)- )- whenM versionSupportsUnlockedPointers $ do- configureSmudgeFilter- scanUnlockedFiles- unlessM isBareRepo $ do- hookWrite postCheckoutHook- hookWrite postMergeHook+ setVersion (fromMaybe defaultVersion mversion)+ configureSmudgeFilter+ showSideAction "scanning for unlocked files"+ scanUnlockedFiles True+ unlessM isBareRepo $ do+ hookWrite postCheckoutHook+ hookWrite postMergeHook AdjustedBranch.checkAdjustedClone >>= \case- AdjustedBranch.NeedUpgradeForAdjustedClone -> - void $ upgrade True versionForAdjustedClone AdjustedBranch.InAdjustedClone -> return () AdjustedBranch.NotInAdjustedClone -> ifM (crippledFileSystem <&&> (not <$> isBareRepo))- ( adjustToCrippledFilesystem+ ( AdjustedBranch.adjustToCrippledFileSystem -- Handle case where this repo was cloned from a -- direct mode repo , unlessM isBareRepo- switchHEADBack+ Direct.switchHEADBack ) propigateSecureHashesOnly createInodeSentinalFile False@@ -150,9 +144,9 @@ ensureInitialized = getVersion >>= maybe needsinit checkUpgrade where needsinit = ifM Annex.Branch.hasSibling- ( initialize Nothing Nothing- , giveup "First run: git-annex init"- )+ ( initialize Nothing Nothing+ , giveup $ "First run: git-annex init"+ ) {- Checks if a repository is initialized. Does not check version for ugrade. -} isInitialized :: Annex Bool@@ -161,7 +155,7 @@ {- A crippled filesystem is one that does not allow making symlinks, - or removing write access from files. -} probeCrippledFileSystem :: Annex Bool-probeCrippledFileSystem = withOtherTmp $ \tmp -> do+probeCrippledFileSystem = withEventuallyCleanedOtherTmp $ \tmp -> do (r, warnings) <- liftIO $ probeCrippledFileSystem' tmp mapM_ warning warnings return r@@ -218,14 +212,15 @@ #ifdef mingw32_HOST_OS return True #else- withOtherTmp $ \tmp -> do+ withEventuallyCleanedOtherTmp $ \tmp -> do let f = tmp </> "lockprobe" mode <- annexFileMode liftIO $ do nukeFile f- ok <- catchBoolIO $ do- Posix.dropLock =<< Posix.lockExclusive (Just mode) f- return True+ let locktest = + Posix.lockExclusive (Just mode) f+ >>= Posix.dropLock+ ok <- isRight <$> tryNonAsync locktest nukeFile f return ok #endif@@ -235,7 +230,7 @@ #ifdef mingw32_HOST_OS return False #else- withOtherTmp $ \tmp -> do+ withEventuallyCleanedOtherTmp $ \tmp -> do let f = tmp </> "gaprobe" let f2 = tmp </> "gaprobe2" liftIO $ do@@ -281,22 +276,3 @@ propigateSecureHashesOnly = maybe noop (setConfig (ConfigKey "annex.securehashesonly")) =<< getGlobalConfig "annex.securehashesonly"--adjustToCrippledFilesystem :: Annex ()-adjustToCrippledFilesystem = ifM versionSupportsAdjustedBranch- ( ifM (liftIO $ AdjustedBranch.isGitVersionSupported)- ( AdjustedBranch.adjustToCrippledFileSystem- , enableDirectMode - )- , enableDirectMode- )--enableDirectMode :: Annex ()-enableDirectMode = unlessM isDirect $ do- warning "Enabling direct mode."- top <- fromRepo Git.repoPath- (l, clean) <- inRepo $ Git.LsFiles.inRepo [top]- forM_ l $ \f ->- maybe noop (`toDirect` f) =<< isAnnexLink f- void $ liftIO clean- setDirect True
Annex/Locations.hs view
@@ -266,7 +266,8 @@ gitAnnexTmpOtherLock :: Git.Repo -> FilePath gitAnnexTmpOtherLock r = gitAnnexDir r </> "othertmp.lck" -{- Tmp directory used by old versions of git-annex. -}+{- .git/annex/misctmp/ was used by old versions of git-annex and is still+ - used during initialization -} gitAnnexTmpOtherDirOld :: Git.Repo -> FilePath gitAnnexTmpOtherDirOld r = addTrailingPathSeparator $ gitAnnexDir r </> "misctmp"
− Annex/MakeRepo.hs
@@ -1,90 +0,0 @@-{- making local repositories (used by webapp mostly)- -- - Copyright 2012-2014 Joey Hess <id@joeyh.name>- -- - Licensed under the GNU AGPL version 3 or higher.- -}--module Annex.MakeRepo where--import Assistant.WebApp.Common-import Annex.Init-import qualified Git.Construct-import qualified Git.Config-import qualified Git.Command-import qualified Git.Branch-import qualified Annex-import Annex.UUID-import Annex.Direct-import Annex.Action-import Types.StandardGroups-import Logs.PreferredContent-import qualified Annex.Branch-import Utility.Process.Transcript--{- Makes a new git repository. Or, if a git repository already- - exists, returns False. -}-makeRepo :: FilePath -> Bool -> IO Bool-makeRepo path bare = ifM (probeRepoExists path)- ( return False- , do- (transcript, ok) <-- processTranscript "git" (toCommand params) Nothing- unless ok $- error $ "git init failed!\nOutput:\n" ++ transcript- return True- )- where- baseparams = [Param "init", Param "--quiet"]- params- | bare = baseparams ++ [Param "--bare", File path]- | otherwise = baseparams ++ [File path]--{- Runs an action in the git repository in the specified directory. -}-inDir :: FilePath -> Annex a -> IO a-inDir dir a = do- state <- Annex.new =<< Git.Config.read =<< Git.Construct.fromPath dir- Annex.eval state $ a `finally` stopCoProcesses--{- Creates a new repository, and returns its UUID. -}-initRepo :: Bool -> Bool -> FilePath -> Maybe String -> Maybe StandardGroup -> IO UUID-initRepo True primary_assistant_repo dir desc mgroup = inDir dir $ do- initRepo' desc mgroup- {- Initialize the master branch, so things that expect- - to have it will work, before any files are added. -}- unlessM (Git.Config.isBare <$> gitRepo) $- void $ inRepo $ Git.Branch.commitCommand Git.Branch.AutomaticCommit- [ Param "--quiet"- , Param "--allow-empty"- , Param "-m"- , Param "created repository"- ]- {- Repositories directly managed by the assistant use direct mode.- - - - Automatic gc is disabled, as it can be slow. Insted, gc is done- - once a day.- -}- when primary_assistant_repo $ do- setDirect True- inRepo $ Git.Command.run- [Param "config", Param "gc.auto", Param "0"]- getUUID-{- Repo already exists, could be a non-git-annex repo though so- - still initialize it. -}-initRepo False _ dir desc mgroup = inDir dir $ do- initRepo' desc mgroup- getUUID--initRepo' :: Maybe String -> Maybe StandardGroup -> Annex ()-initRepo' desc mgroup = unlessM isInitialized $ do- initialize desc Nothing- u <- getUUID- maybe noop (defaultStandardGroup u) mgroup- {- Ensure branch gets committed right away so it is- - available for merging immediately. -}- Annex.Branch.commit =<< Annex.Branch.commitMessage--{- Checks if a git repo exists at a location. -}-probeRepoExists :: FilePath -> IO Bool-probeRepoExists dir = isJust <$>- catchDefaultIO Nothing (Git.Construct.checkForRepo dir)
Annex/Tmp.hs view
@@ -7,9 +7,8 @@ module Annex.Tmp where -import Common-import Annex-import Annex.Locations+import Annex.Common+import qualified Annex import Annex.LockFile import Annex.Perms import Types.CleanupActions@@ -24,13 +23,30 @@ -- any time. withOtherTmp :: (FilePath -> Annex a) -> Annex a withOtherTmp a = do- addCleanup OtherTmpCleanup cleanupOtherTmp+ Annex.addCleanup OtherTmpCleanup cleanupOtherTmp tmpdir <- fromRepo gitAnnexTmpOtherDir tmplck <- fromRepo gitAnnexTmpOtherLock withSharedLock (const tmplck) $ do void $ createAnnexDirectory tmpdir a tmpdir +-- | This uses an alternate temp directory. The action should normally+-- clean up whatever files it writes there, but if it leaves files+-- there (perhaps due to being interrupted), the files will be eventually+-- cleaned up by another git-annex process (after they're a week old).+--+-- Unlike withOtherTmp, this does not rely on locking working.+-- Its main use is in situations where the state of lockfile is not+-- determined yet, eg during initialization.+withEventuallyCleanedOtherTmp :: (FilePath -> Annex a) -> Annex a+withEventuallyCleanedOtherTmp = bracket setup cleanup+ where+ setup = do+ tmpdir <- fromRepo gitAnnexTmpOtherDirOld+ void $ createAnnexDirectory tmpdir+ return tmpdir+ cleanup = liftIO . void . tryIO . removeDirectory + -- | Cleans up any tmp files that were left by a previous -- git-annex process that got interrupted or failed to clean up after -- itself for some other reason.@@ -42,8 +58,6 @@ void $ tryIO $ tryExclusiveLock (const tmplck) $ do tmpdir <- fromRepo gitAnnexTmpOtherDir void $ liftIO $ tryIO $ removeDirectoryRecursive tmpdir- -- This is only to clean up cruft left by old versions of- -- git-annex; it can be removed eventually. oldtmp <- fromRepo gitAnnexTmpOtherDirOld liftIO $ mapM_ cleanold =<< dirContentsRecursive oldtmp liftIO $ void $ tryIO $ removeDirectory oldtmp -- when empty
Annex/UpdateInstead.hs view
@@ -9,19 +9,15 @@ import qualified Annex import Annex.Common-import Config-import Annex.Version import Annex.AdjustedBranch import Git.Branch import Git.ConfigTypes -{- receive.denyCurrentBranch=updateInstead does not work in direct mode- - repositories or when an adjusted branch is checked out, so must be- - emulated. -}+{- receive.denyCurrentBranch=updateInstead does not work+ - when an adjusted branch is checked out, so must be emulated. -} needUpdateInsteadEmulation :: Annex Bool-needUpdateInsteadEmulation = updateinsteadset <&&> (isDirect <||> isadjusted)+needUpdateInsteadEmulation = updateinsteadset <&&> isadjusted where updateinsteadset = (== UpdateInstead) . receiveDenyCurrentBranch <$> Annex.getGitConfig- isadjusted = versionSupportsUnlockedPointers- <&&> (maybe False (isJust . getAdjustment) <$> inRepo Git.Branch.current)+ isadjusted = (maybe False (isJust . getAdjustment) <$> inRepo Git.Branch.current)
Annex/Version.hs view
@@ -17,19 +17,13 @@ import qualified Data.Map as M defaultVersion :: RepoVersion-defaultVersion = RepoVersion 5+defaultVersion = RepoVersion 7 latestVersion :: RepoVersion latestVersion = RepoVersion 7 supportedVersions :: [RepoVersion]-supportedVersions = map RepoVersion [5, 7]--versionForAdjustedClone :: RepoVersion-versionForAdjustedClone = RepoVersion 7--versionForCrippledFilesystem :: RepoVersion-versionForCrippledFilesystem = RepoVersion 7+supportedVersions = map RepoVersion [7] upgradableVersions :: [RepoVersion] #ifndef mingw32_HOST_OS@@ -42,6 +36,7 @@ autoUpgradeableVersions = M.fromList [ (RepoVersion 3, RepoVersion 5) , (RepoVersion 4, RepoVersion 5)+ , (RepoVersion 5, RepoVersion 6) , (RepoVersion 6, RepoVersion 7) ] @@ -50,24 +45,6 @@ getVersion :: Annex (Maybe RepoVersion) getVersion = annexVersion <$> Annex.getGitConfig--versionSupportsDirectMode :: Annex Bool-versionSupportsDirectMode = go <$> getVersion- where- go (Just v) | v >= RepoVersion 6 = False- go _ = True--versionSupportsUnlockedPointers :: Annex Bool-versionSupportsUnlockedPointers = go <$> getVersion- where- go (Just v) | v >= RepoVersion 6 = True- go _ = False--versionSupportsAdjustedBranch :: Annex Bool-versionSupportsAdjustedBranch = versionSupportsUnlockedPointers--versionUsesKeysDatabase :: Annex Bool-versionUsesKeysDatabase = versionSupportsUnlockedPointers setVersion :: RepoVersion -> Annex () setVersion (RepoVersion v) = setConfig versionField (show v)
Annex/WorkTree.hs view
@@ -10,13 +10,11 @@ import Annex.Common import Annex.Link import Annex.CatFile-import Annex.Version import Annex.Content import Annex.ReplaceFile import Annex.CurrentBranch import Annex.InodeSentinal import Utility.InodeCache-import Config import Git.FilePath import qualified Git.Ref import qualified Git.LsTree@@ -55,10 +53,7 @@ lookupFile' :: (FilePath -> Annex (Maybe Key)) -> FilePath -> Annex (Maybe Key) lookupFile' catkeyfile file = isAnnexLink file >>= \case Just key -> return (Just key)- Nothing -> ifM (versionSupportsUnlockedPointers <||> isDirect)- ( catkeyfile file- , return Nothing - )+ Nothing -> catkeyfile file {- Modifies an action to only act on files that are already annexed, - and passes the key on to it. -}@@ -75,11 +70,11 @@ - when initializing/upgrading a v6+ mode repository. - - Also, the content for the unlocked file may already be present as- - an annex object. If so, make the unlocked file use that content.+ - an annex object. If so, make the unlocked file use that content+ - when replacefiles is True. -}-scanUnlockedFiles :: Annex ()-scanUnlockedFiles = whenM (inRepo Git.Ref.headExists) $ do- showSideAction "scanning for unlocked files"+scanUnlockedFiles :: Bool -> Annex ()+scanUnlockedFiles replacefiles = whenM (inRepo Git.Ref.headExists) $ do Database.Keys.runWriter $ liftIO . Database.Keys.SQL.dropAllAssociatedFiles (l, cleanup) <- inRepo $ Git.LsTree.lsTree Git.LsTree.LsTreeRecursive Git.Ref.headRef@@ -97,7 +92,7 @@ let tf = Git.LsTree.file i Database.Keys.runWriter $ liftIO . Database.Keys.SQL.addAssociatedFileFast (toIKey k) tf- whenM (inAnnex k) $ do+ whenM (pure replacefiles <&&> inAnnex k) $ do f <- fromRepo $ fromTopFilePath tf destmode <- liftIO $ catchMaybeIO $ fileMode <$> getFileStatus f ic <- replaceFile f $ \tmp ->
+ Assistant/MakeRepo.hs view
@@ -0,0 +1,93 @@+{- making local repositories+ -+ - Copyright 2012-2014 Joey Hess <id@joeyh.name>+ -+ - Licensed under the GNU AGPL version 3 or higher.+ -}++module Assistant.MakeRepo where++import Assistant.WebApp.Common+import Annex.Init+import qualified Git.Construct+import qualified Git.Config+import qualified Git.Command+import qualified Git.Branch+import qualified Annex+import Annex.UUID+import Annex.AdjustedBranch+import Annex.Action+import Types.StandardGroups+import Logs.PreferredContent+import qualified Annex.Branch+import Utility.Process.Transcript+import Config++{- Makes a new git repository. Or, if a git repository already+ - exists, returns False. -}+makeRepo :: FilePath -> Bool -> IO Bool+makeRepo path bare = ifM (probeRepoExists path)+ ( return False+ , do+ (transcript, ok) <-+ processTranscript "git" (toCommand params) Nothing+ unless ok $+ error $ "git init failed!\nOutput:\n" ++ transcript+ return True+ )+ where+ baseparams = [Param "init", Param "--quiet"]+ params+ | bare = baseparams ++ [Param "--bare", File path]+ | otherwise = baseparams ++ [File path]++{- Runs an action in the git repository in the specified directory. -}+inDir :: FilePath -> Annex a -> IO a+inDir dir a = do+ state <- Annex.new =<< Git.Config.read =<< Git.Construct.fromPath dir+ Annex.eval state $ a `finally` stopCoProcesses++{- Creates a new repository, and returns its UUID. -}+initRepo :: Bool -> Bool -> FilePath -> Maybe String -> Maybe StandardGroup -> IO UUID+initRepo True primary_assistant_repo dir desc mgroup = inDir dir $ do+ initRepo' desc mgroup+ {- Initialize the master branch, so things that expect+ - to have it will work, before any files are added. -}+ unlessM (Git.Config.isBare <$> gitRepo) $+ void $ inRepo $ Git.Branch.commitCommand Git.Branch.AutomaticCommit+ [ Param "--quiet"+ , Param "--allow-empty"+ , Param "-m"+ , Param "created repository"+ ]+ {- Repositories directly managed by the assistant use + - an adjusted unlocked branch with annex.thin set.+ - + - Automatic gc is disabled, as it can be slow. Insted, gc is done+ - once a day.+ -}+ when primary_assistant_repo $ do+ void $ enterAdjustedBranch (LinkAdjustment UnlockAdjustment)+ setConfig (annexConfig "thin") (Git.Config.boolConfig True)+ inRepo $ Git.Command.run+ [Param "config", Param "gc.auto", Param "0"]+ getUUID+{- Repo already exists, could be a non-git-annex repo though so+ - still initialize it. -}+initRepo False _ dir desc mgroup = inDir dir $ do+ initRepo' desc mgroup+ getUUID++initRepo' :: Maybe String -> Maybe StandardGroup -> Annex ()+initRepo' desc mgroup = unlessM isInitialized $ do+ initialize desc Nothing+ u <- getUUID+ maybe noop (defaultStandardGroup u) mgroup+ {- Ensure branch gets committed right away so it is+ - available for merging immediately. -}+ Annex.Branch.commit =<< Annex.Branch.commitMessage++{- Checks if a git repo exists at a location. -}+probeRepoExists :: FilePath -> IO Bool+probeRepoExists dir = isJust <$>+ catchDefaultIO Nothing (Git.Construct.checkForRepo dir)
Assistant/Threads/Committer.hs view
@@ -20,7 +20,6 @@ import Types.Transfer import Logs.Location import qualified Annex.Queue-import qualified Git.LsFiles import Utility.ThreadScheduler import qualified Utility.Lsof as Lsof import qualified Utility.DirWatcher as DirWatcher@@ -32,11 +31,9 @@ import Annex.Perms import Annex.CatFile import Annex.InodeSentinal-import Annex.Version import Annex.CurrentBranch import qualified Annex import Utility.InodeCache-import Annex.Content.Direct import qualified Database.Keys import qualified Command.Sync import qualified Git.Branch@@ -54,8 +51,7 @@ commitThread = namedThread "Committer" $ do havelsof <- liftIO $ inPath "lsof" delayadd <- liftAnnex $- maybe delayaddDefault (return . Just . Seconds)- =<< annexDelayAdd <$> Annex.getGitConfig+ fmap Seconds . annexDelayAdd <$> Annex.getGitConfig msg <- liftAnnex Command.Sync.commitMsg lockdowndir <- liftAnnex $ fromRepo gitAnnexTmpWatcherDir liftAnnex $ do@@ -240,19 +236,6 @@ Command.Sync.updateBranches =<< getCurrentBranch return ok -{- OSX needs a short delay after a file is added before locking it down,- - as pasting a file seems to try to set file permissions or otherwise- - access the file after closing it. -}-delayaddDefault :: Annex (Maybe Seconds)-#ifdef darwin_HOST_OS-delayaddDefault = ifM (isDirect <||> versionSupportsUnlockedPointers)- ( return Nothing- , return $ Just $ Seconds 1- )-#else-delayaddDefault = return Nothing-#endif- {- If there are PendingAddChanges, or InProcessAddChanges, the files - have not yet actually been added to the annex, and that has to be done - now, before committing.@@ -275,50 +258,22 @@ handleAdds :: FilePath -> Bool -> Maybe Seconds -> [Change] -> Assistant [Change] handleAdds lockdowndir havelsof delayadd cs = returnWhen (null incomplete) $ do let (pending, inprocess) = partition isPendingAddChange incomplete- direct <- liftAnnex isDirect- unlocked <- liftAnnex versionSupportsUnlockedPointers- let lockingfiles = not (unlocked || direct) let lockdownconfig = LockDownConfig- { lockingFile = lockingfiles+ { lockingFile = False , hardlinkFileTmpDir = Just lockdowndir }- (pending', cleanup) <- if unlocked || direct- then return (pending, noop)- else findnew pending (postponed, toadd) <- partitionEithers- <$> safeToAdd lockdowndir lockdownconfig havelsof delayadd pending' inprocess- cleanup+ <$> safeToAdd lockdowndir lockdownconfig havelsof delayadd pending inprocess unless (null postponed) $ refillChanges postponed returnWhen (null toadd) $ do added <- addaction toadd $- catMaybes <$>- if not lockingfiles- then addunlocked direct toadd- else forM toadd (add lockdownconfig)- if DirWatcher.eventsCoalesce || null added || unlocked || direct- then return $ added ++ otherchanges- else do- r <- handleAdds lockdowndir havelsof delayadd =<< getChanges- return $ r ++ added ++ otherchanges+ catMaybes <$> addunlocked toadd+ return $ added ++ otherchanges where (incomplete, otherchanges) = partition (\c -> isPendingAddChange c || isInProcessAddChange c) cs- - -- Find files that are actually new, and not unlocked annexed- -- files. The ls-files is run on a batch of files.- findnew [] = return ([], noop)- findnew pending@(exemplar:_) = do- let segments = segmentXargsUnordered $ map changeFile pending- rs <- liftAnnex $ forM segments $ \fs ->- inRepo (Git.LsFiles.notInRepo False fs)- let (newfiles, cleanup) = foldl'- (\(l1, a1) (l2, a2) -> (l1 ++ l2, a1 >> a2))- ([], return True) rs- -- note: timestamp info is lost here- let ts = changeTime exemplar- return (map (PendingAddChange ts) newfiles, void $ liftIO cleanup) returnWhen c a | c = return otherchanges@@ -330,10 +285,10 @@ where ks = keySource ld doadd = sanitycheck ks $ do- (mkey, mcache) <- liftAnnex $ do+ (mkey, _mcache) <- liftAnnex $ do showStart "add" $ keyFilename ks ingest nullMeterUpdate (Just $ LockedDown lockdownconfig ks) Nothing- maybe (failedingest change) (done change mcache $ keyFilename ks) mkey+ maybe (failedingest change) (done change $ keyFilename ks) mkey add _ _ = return Nothing {- Avoid overhead of re-injesting a renamed unlocked file, by@@ -341,10 +296,10 @@ - same InodeCache as the new file. If so, we can just update - bookkeeping, and stage the file in git. -}- addunlocked :: Bool -> [Change] -> Assistant [Maybe Change]- addunlocked isdirect toadd = do+ addunlocked :: [Change] -> Assistant [Maybe Change]+ addunlocked toadd = do ct <- liftAnnex compareInodeCachesWith- m <- liftAnnex $ removedKeysMap isdirect ct cs+ m <- liftAnnex $ removedKeysMap ct cs delta <- liftAnnex getTSDelta let cfg = LockDownConfig { lockingFile = False@@ -359,46 +314,32 @@ Just cache -> case M.lookup (inodeCacheToKey ct cache) m of Nothing -> add cfg c- Just k -> fastadd isdirect c k+ Just k -> fastadd c k - fastadd :: Bool -> Change -> Key -> Assistant (Maybe Change)- fastadd isdirect change key = do+ fastadd :: Change -> Key -> Assistant (Maybe Change)+ fastadd change key = do let source = keySource $ lockedDown change- liftAnnex $ if isdirect- then finishIngestDirect key source- else finishIngestUnlocked key source- done change Nothing (keyFilename source) key+ liftAnnex $ finishIngestUnlocked key source+ done change (keyFilename source) key - removedKeysMap :: Bool -> InodeComparisonType -> [Change] -> Annex (M.Map InodeCacheKey Key)- removedKeysMap isdirect ct l = do+ removedKeysMap :: InodeComparisonType -> [Change] -> Annex (M.Map InodeCacheKey Key)+ removedKeysMap ct l = do mks <- forM (filter isRmChange l) $ \c -> catKeyFile $ changeFile c M.fromList . concat <$> mapM mkpairs (catMaybes mks) where mkpairs k = map (\c -> (inodeCacheToKey ct c, k)) <$>- if isdirect- then recordedInodeCache k- else Database.Keys.getInodeCaches k+ Database.Keys.getInodeCaches k failedingest change = do refill [retryChange change] liftAnnex showEndFail return Nothing - done change mcache file key = liftAnnex $ do+ done change file key = liftAnnex $ do logStatus key InfoPresent- ifM versionSupportsUnlockedPointers- ( do- mode <- liftIO $ catchMaybeIO $ fileMode <$> getFileStatus file- stagePointerFile file mode =<< hashPointerFile key- , do- link <- ifM isDirect- ( calcRepo $ gitAnnexLink file key- , makeLink file key mcache- )- whenM (pure DirWatcher.eventsCoalesce <||> isDirect) $- stageSymlink file =<< hashSymlink link- )+ mode <- liftIO $ catchMaybeIO $ fileMode <$> getFileStatus file+ stagePointerFile file mode =<< hashPointerFile key showEndOk return $ Just $ finishedChange change key
Assistant/Threads/SanityChecker.hs view
@@ -32,7 +32,6 @@ import qualified Assistant.Threads.Watcher as Watcher import Utility.Batch import Utility.NotificationBroadcaster-import Config import Utility.HumanTime import Utility.Tense import Git.Repair@@ -200,8 +199,7 @@ liftAnnex $ warning msg void $ addAlert $ sanityCheckFixAlert msg addsymlink file s = do- isdirect <- liftAnnex isDirect- Watcher.runHandler (Watcher.onAddSymlink isdirect) file s+ Watcher.runHandler Watcher.onAddSymlink file s insanity $ "found unstaged symlink: " ++ file hourlyCheck :: Assistant ()
Assistant/Threads/Watcher.hs view
@@ -23,25 +23,22 @@ import Assistant.Alert import Utility.DirWatcher import Utility.DirWatcher.Types+import Utility.InodeCache import qualified Annex import qualified Annex.Queue import qualified Git import qualified Git.UpdateIndex import qualified Git.LsFiles as LsFiles import Annex.WorkTree-import Annex.Direct-import Annex.Content.Direct import Annex.CatFile import Annex.CheckIgnore import Annex.Link import Annex.FileMatcher import Annex.Content import Annex.ReplaceFile-import Annex.Version import Annex.InodeSentinal import Git.Types import Git.FilePath-import Config import Config.GitConfig import Utility.ThreadScheduler import Logs.Location@@ -92,16 +89,10 @@ runWatcher = do startup <- asIO1 startupScan matcher <- liftAnnex largeFilesMatcher- direct <- liftAnnex isDirect- unlocked <- liftAnnex versionSupportsUnlockedPointers symlinkssupported <- liftAnnex $ coreSymlinks <$> Annex.getGitConfig- addhook <- hook $ if unlocked- then onAddUnlocked symlinkssupported matcher- else if direct- then onAddDirect symlinkssupported matcher- else onAdd matcher+ addhook <- hook $ onAddUnlocked symlinkssupported matcher delhook <- hook onDel- addsymlinkhook <- hook $ onAddSymlink direct+ addsymlinkhook <- hook onAddSymlink deldirhook <- hook onDelDir errhook <- hook onErr let hooks = mkWatchHooks@@ -210,13 +201,6 @@ madeChange file AddFileChange ) -onAdd :: GetFileMatcher -> Handler-onAdd matcher file filestatus- | maybe False isRegularFile filestatus =- unlessIgnored file $- add matcher file- | otherwise = noChange- shouldRestage :: DaemonStatus -> Bool shouldRestage ds = scanComplete ds || forceRestage ds @@ -224,7 +208,7 @@ onAddUnlocked symlinkssupported matcher f fs = do mk <- liftIO $ isPointerFile f case mk of- Nothing -> onAddUnlocked' False contentchanged addassociatedfile addlink samefilestatus symlinkssupported matcher f fs+ Nothing -> onAddUnlocked' contentchanged addassociatedfile addlink samefilestatus symlinkssupported matcher f fs Just k -> addlink f k where addassociatedfile key file = @@ -247,27 +231,15 @@ liftAnnex $ stagePointerFile file mode =<< hashPointerFile key madeChange file $ LinkChange (Just key) -{- In direct mode, add events are received for both new files, and- - modified existing files.- -}-onAddDirect :: Bool -> GetFileMatcher -> Handler-onAddDirect = onAddUnlocked' True changedDirect addassociatedfile addlink sameFileStatus- where- addassociatedfile key file = void $ addAssociatedFile key file- addlink file key = do- link <- liftAnnex $ calcRepo $ gitAnnexLink file key- addLink file link (Just key)- onAddUnlocked'- :: Bool- -> (Key -> FilePath -> Annex ())+ :: (Key -> FilePath -> Annex ()) -> (Key -> FilePath -> Annex ()) -> (FilePath -> Key -> Assistant (Maybe Change)) -> (Key -> FilePath -> FileStatus -> Annex Bool) -> Bool -> GetFileMatcher -> Handler-onAddUnlocked' isdirect contentchanged addassociatedfile addlink samefilestatus symlinkssupported matcher file fs = do+onAddUnlocked' contentchanged addassociatedfile addlink samefilestatus symlinkssupported matcher file fs = do v <- liftAnnex $ catKeyFile file case (v, fs) of (Just key, Just filestatus) ->@@ -306,31 +278,28 @@ Nothing -> noop Just key -> liftAnnex $ addassociatedfile key file- onAddSymlink' (Just $ fromRawFilePath lt) mk isdirect file fs+ onAddSymlink' (Just $ fromRawFilePath lt) mk file fs {- A symlink might be an arbitrary symlink, which is just added. - Or, if it is a git-annex symlink, ensure it points to the content - before adding it. -}-onAddSymlink :: Bool -> Handler-onAddSymlink isdirect file filestatus = unlessIgnored file $ do+onAddSymlink :: Handler+onAddSymlink file filestatus = unlessIgnored file $ do linktarget <- liftIO (catchMaybeIO $ readSymbolicLink file) kv <- liftAnnex (lookupFile file)- onAddSymlink' linktarget kv isdirect file filestatus+ onAddSymlink' linktarget kv file filestatus -onAddSymlink' :: Maybe String -> Maybe Key -> Bool -> Handler-onAddSymlink' linktarget mk isdirect file filestatus = go mk+onAddSymlink' :: Maybe String -> Maybe Key -> Handler+onAddSymlink' linktarget mk file filestatus = go mk where go (Just key) = do- when isdirect $- liftAnnex $ void $ addAssociatedFile key file link <- liftAnnex $ calcRepo $ gitAnnexLink file key if linktarget == Just link then ensurestaged (Just link) =<< getDaemonStatus else do- unless isdirect $- liftAnnex $ replaceFile file $- makeAnnexLink link+ liftAnnex $ replaceFile file $+ makeAnnexLink link addLink file link (Just key) -- other symlink, not git-annex go Nothing = ensurestaged linktarget =<< getDaemonStatus@@ -376,11 +345,7 @@ onDel' :: FilePath -> Annex () onDel' file = do topfile <- inRepo (toTopFilePath file)- ifM versionSupportsUnlockedPointers- ( withkey $ flip Database.Keys.removeAssociatedFile topfile- , whenM isDirect $- withkey $ \key -> void $ removeAssociatedFile key file- )+ withkey $ flip Database.Keys.removeAssociatedFile topfile Annex.Queue.addUpdateIndex =<< inRepo (Git.UpdateIndex.unstageFile file) where
Assistant/Upgrade.hs view
@@ -113,7 +113,7 @@ | transferDirection t == Download = do debug ["finished downloading git-annex distribution"] maybe (failedupgrade "bad download") go- =<< liftAnnex (withObjectLoc k fsckit (getM fsckit))+ =<< liftAnnex (withObjectLoc k fsckit) | otherwise = cleanup where k = distributionKey d
Assistant/WebApp/Configurators/Local.hs view
@@ -15,7 +15,7 @@ import Assistant.WebApp.MakeRemote import Assistant.Sync import Assistant.Restart-import Annex.MakeRepo+import Assistant.MakeRepo import qualified Annex import qualified Git import qualified Git.Config
Build/BundledPrograms.hs view
@@ -83,5 +83,7 @@ -- its kernel, and avoid using them if not available. ] where+#ifndef mingw32_HOST_OS ifset True s = Just s ifset False _ = Nothing+#endif
Build/Configure.hs view
@@ -62,7 +62,7 @@ go (Just s) = return $ Config "gitversion" $ StringConfig s go Nothing = do v <- Git.Version.installed- let oldestallowed = Git.Version.normalize "1.7.1.0"+ let oldestallowed = Git.Version.normalize "2.1" when (v < oldestallowed) $ error $ "installed git version " ++ show v ++ " is too old! (Need " ++ show oldestallowed ++ " or newer)" return $ Config "gitversion" $ StringConfig $ show v
CHANGELOG view
@@ -1,3 +1,43 @@+git-annex (7.20190912) upstream; urgency=medium++ * Default to v7 for new repositories.+ * Automatically upgrade v5 repositories to v7.+ * Automatically convert direct mode repositories to v7 with adjusted+ unlocked branches and set annex.thin.+ * Added annex.autoupgraderepository configuration that can be set to false+ to prevent any automatic repository upgrades.+ * Refuse to upgrade direct mode repositories when git is older than 2.22,+ which fixed a memory leak that could cause an OOM during the upgrade.+ * Removed support for git versions older than 2.1.+ * assistant: When creating a new repository, no longer use direct+ mode, instead use v7 adjusted branches with annex.thin.+ * init: When run on a crippled filesystem with --version=5,+ will error out, since version 7 is needed for adjusted unlocked branch.+ * direct: This command always errors out as direct mode is no longer+ supported.+ * indirect: This command has become a deprecated noop.+ * proxy: This command is deprecated because it was only needed in direct+ mode. (But it continues to work.)+ * info: Removed the "repository mode" from its output (including the+ --json output) since with the removal of direct mode, there is no+ repository mode.+ * info: When file matching options are specified when getting+ info of something other than a directory, they won't have any effect,+ so error out to avoid confusion.+ * info: Display trust level when getting info on a uuid, same as a remote.+ * When upgrading a direct mode repo to v7 with adjusted unlocked branches,+ fix a bug that prevented annex.thin from taking effect for the files+ in working tree.+ * Avoid making a commit when upgrading from direct mode to v7.+ * init: Catch more exceptions when testing locking.+ * init: Fix a reversion that broke initialization on systems that+ need to use pid locking.+ * A git-annex-standalone rpm is now distributed along with the standalone+ tarball.+ * Added standalone/rpm/rpmbuild-from-standalone-tarball script.++ -- Joey Hess <id@joeyh.name> Fri, 13 Sep 2019 12:53:06 -0400+ git-annex (7.20190819) upstream; urgency=medium * New git-lfs special remote, which can be used to store data on any git-lfs
CmdLine/Seek.hs view
@@ -114,38 +114,21 @@ withFilesToBeCommitted a l = seekActions $ prepFiltered a $ seekHelper LsFiles.stagedNotDeleted l -withFilesOldUnlocked :: (FilePath -> CommandSeek) -> [WorkTreeItem] -> CommandSeek-withFilesOldUnlocked = withFilesOldUnlocked' LsFiles.typeChanged--{- Unlocked files before v6 have changed type from a symlink to a regular file.- -- - Furthermore, unlocked files used to be a git-annex symlink,- - not some other sort of symlink.- -}-withFilesOldUnlocked' :: ([FilePath] -> Git.Repo -> IO ([FilePath], IO Bool)) -> (FilePath -> CommandSeek) -> [WorkTreeItem] -> CommandSeek-withFilesOldUnlocked' typechanged a l = seekActions $- prepFiltered a unlockedfiles- where- unlockedfiles = filterM isOldUnlocked =<< seekHelper typechanged l- isOldUnlocked :: FilePath -> Annex Bool isOldUnlocked f = liftIO (notSymlink f) <&&> (isJust <$> catKeyFile f <||> isJust <$> catKeyFileHEAD f) -withFilesOldUnlockedToBeCommitted :: (FilePath -> CommandSeek) -> [WorkTreeItem] -> CommandSeek-withFilesOldUnlockedToBeCommitted = withFilesOldUnlocked' LsFiles.typeChangedStaged--{- v6 unlocked pointer files that are staged, and whose content has not been+{- unlocked pointer files that are staged, and whose content has not been - modified-} withUnmodifiedUnlockedPointers :: (FilePath -> CommandSeek) -> [WorkTreeItem] -> CommandSeek withUnmodifiedUnlockedPointers a l = seekActions $ prepFiltered a unlockedfiles where- unlockedfiles = filterM isV6UnmodifiedUnlocked + unlockedfiles = filterM isUnmodifiedUnlocked =<< seekHelper LsFiles.typeChangedStaged l -isV6UnmodifiedUnlocked :: FilePath -> Annex Bool-isV6UnmodifiedUnlocked f = catKeyFile f >>= \case+isUnmodifiedUnlocked :: FilePath -> Annex Bool+isUnmodifiedUnlocked f = catKeyFile f >>= \case Nothing -> return False Just k -> sameInodeCache f =<< Database.Keys.getInodeCaches k
Command.hs view
@@ -24,7 +24,6 @@ import Options.Applicative as ReExported hiding (command) import qualified Git import Annex.Init-import Config import Utility.Daemon import Types.Transfer import Types.ActionItem@@ -119,10 +118,6 @@ repoExists :: CommandCheck repoExists = CommandCheck 0 ensureInitialized--notDirect :: Command -> Command-notDirect = addCheck $ whenM isDirect $- giveup "You cannot run this command in a direct mode repository." notBareRepo :: Command -> Command notBareRepo = addCheck $ whenM (fromRepo Git.repoIsLocalBare) $
Command/Add.hs view
@@ -11,14 +11,11 @@ import Annex.Ingest import Logs.Location import Annex.Content-import Annex.Content.Direct import qualified Annex import qualified Annex.Queue import qualified Database.Keys-import Config import Annex.FileMatcher import Annex.Link-import Annex.Version import Annex.Tmp import Messages.Progress import Git.FilePath@@ -71,11 +68,7 @@ unless (updateOnly o) $ go (withFilesNotInGit (not $ includeDotFiles o)) go withFilesMaybeModified- ifM versionSupportsUnlockedPointers- ( go withUnmodifiedUnlockedPointers- , unlessM isDirect $- go withFilesOldUnlocked- )+ go withUnmodifiedUnlockedPointers {- Pass file off to git-add. -} startSmall :: FilePath -> CommandStart@@ -95,12 +88,8 @@ start :: FilePath -> CommandStart start file = do- ifM versionSupportsUnlockedPointers- ( do- mk <- liftIO $ isPointerFile file- maybe go fixuppointer mk- , go- )+ mk <- liftIO $ isPointerFile file+ maybe go fixuppointer mk where go = ifAnnexed file addpresent add add = liftIO (catchMaybeIO $ getSymbolicLinkStatus file) >>= \case@@ -112,18 +101,10 @@ if isSymbolicLink s then next $ addFile file else perform file- addpresent key = ifM versionSupportsUnlockedPointers- ( liftIO (catchMaybeIO $ getSymbolicLinkStatus file) >>= \case+ addpresent key = + liftIO (catchMaybeIO $ getSymbolicLinkStatus file) >>= \case Just s | isSymbolicLink s -> fixuplink key _ -> add- , ifM isDirect- ( liftIO (catchMaybeIO $ getSymbolicLinkStatus file) >>= \case- Just s | isSymbolicLink s -> fixuplink key- _ -> ifM (goodContent key file)- ( stop , add )- , fixuplink key- )- ) fixuplink key = starting "add" (ActionItemWorkTreeFile file) $ do -- the annexed symlink is present but not yet added to git liftIO $ removeFile file
Command/AddUnused.hs view
@@ -13,10 +13,9 @@ import Command.Unused (withUnusedMaps, UnusedMaps(..), startUnused) cmd :: Command-cmd = notDirect $ - command "addunused" SectionMaintenance - "add back unused files"- (paramRepeating paramNumRange) (withParams seek)+cmd = command "addunused" SectionMaintenance + "add back unused files"+ (paramRepeating paramNumRange) (withParams seek) seek :: CmdParams -> CommandSeek seek = withUnusedMaps start
Command/Adjust.hs view
@@ -11,7 +11,7 @@ import Annex.AdjustedBranch cmd :: Command-cmd = notBareRepo $ notDirect $ noDaemonRunning $+cmd = notBareRepo $ noDaemonRunning $ command "adjust" SectionSetup "enter adjusted branch" paramNothing (seek <$$> optParser)
Command/DiffDriver.hs view
@@ -90,12 +90,7 @@ v <- getAnnexLinkTarget' (getfile r) False case parseLinkTargetOrPointer =<< v of Nothing -> return r- Just k -> setfile r <$>- withObjectLoc k- -- indirect mode- return - -- direct mode- (return . Prelude.head)+ Just k -> withObjectLoc k (pure . setfile r) _ -> return r externalDiffer :: String -> [String] -> Differ
Command/Direct.hs view
@@ -8,60 +8,14 @@ module Command.Direct where import Command-import qualified Git-import qualified Git.LsFiles-import qualified Git.Branch-import Config-import Annex.Direct-import Annex.Version cmd :: Command cmd = notBareRepo $ noDaemonRunning $- command "direct" SectionSetup "switch repository to direct mode"+ command "direct" SectionSetup "switch repository to direct mode (deprecated)" paramNothing (withParams seek) seek :: CmdParams -> CommandSeek seek = withNothing (commandAction start) start :: CommandStart-start = ifM versionSupportsDirectMode- ( ifM isDirect- ( stop - , starting "direct" (ActionItemOther Nothing)- perform- )- , giveup "Direct mode is not supported by this repository version. Use git-annex unlock instead."- )--perform :: CommandPerform-perform = do- showOutput- _ <- inRepo $ Git.Branch.commitCommand Git.Branch.ManualCommit- [ Param "-a"- , Param "-m"- , Param "commit before switching to direct mode"- ]-- top <- fromRepo Git.repoPath- (l, clean) <- inRepo $ Git.LsFiles.inRepo [top]- forM_ l go- void $ liftIO clean- next cleanup- where- go = whenAnnexed $ \f k -> do- toDirectGen k f >>= \case- Nothing -> noop- Just a -> tryNonAsync a >>= \case- Left e -> warnlocked f e- Right _ -> return ()- return Nothing-- warnlocked :: FilePath -> SomeException -> Annex ()- warnlocked f e = do- warning $ f ++ ": " ++ show e- warning "leaving this file as-is; correct this problem and run git annex fsck on it"--cleanup :: CommandCleanup-cleanup = do- setDirect True- return True+start = giveup "Direct mode is not supported by this repository version. Use git-annex unlock instead."
Command/EnableTor.hs view
@@ -41,7 +41,11 @@ -- This runs as root, so avoid making any commits or initializing -- git-annex, or doing other things that create root-owned files. start :: [String] -> CommandStart+#ifndef mingw32_HOST_OS start os = do+#else+start _os = do+#endif uuid <- getUUID when (uuid == NoUUID) $ giveup "This can only be run in a git-annex repository."
Command/Fix.hs view
@@ -12,7 +12,6 @@ import Command import Config import qualified Annex-import Annex.Version import Annex.ReplaceFile import Annex.Content import Annex.Perms@@ -25,19 +24,15 @@ #endif cmd :: Command-cmd = notDirect $ noCommit $ withGlobalOptions [annexedMatchingOptions] $+cmd = noCommit $ withGlobalOptions [annexedMatchingOptions] $ command "fix" SectionMaintenance "fix up links to annexed content" paramPaths (withParams seek) seek :: CmdParams -> CommandSeek seek ps = unlessM crippledFileSystem $ do - fixwhat <- ifM versionSupportsUnlockedPointers- ( return FixAll- , return FixSymlinks- ) withFilesInGit- (commandAction . (whenAnnexed $ start fixwhat))+ (commandAction . (whenAnnexed $ start FixAll)) =<< workTreeItems ps data FixWhat = FixSymlinks | FixAll
Command/FromKey.hs view
@@ -19,7 +19,7 @@ import Network.URI cmd :: Command-cmd = notDirect $ notBareRepo $ withGlobalOptions [jsonOptions] $+cmd = notBareRepo $ withGlobalOptions [jsonOptions] $ command "fromkey" SectionPlumbing "adds a file using a specific key" (paramRepeating (paramPair paramKey paramPath)) (seek <$$> optParser)
Command/Fsck.hs view
@@ -15,8 +15,6 @@ import qualified Types.Backend import qualified Backend import Annex.Content-import qualified Annex.Content.Direct as Direct-import Annex.Direct import Annex.Perms import Annex.Link import Logs.Location@@ -28,7 +26,6 @@ import Annex.UUID import Annex.ReplaceFile import Utility.DataUnits-import Config import Utility.HumanTime import Utility.CopyFile import Git.FilePath@@ -225,16 +222,15 @@ - in this repository only. -} verifyLocationLog :: Key -> KeyStatus -> ActionItem -> Annex Bool verifyLocationLog key keystatus ai = do- direct <- isDirect obj <- calcRepo $ gitAnnexLocation key- present <- if not direct && isKeyUnlockedThin keystatus+ present <- if isKeyUnlockedThin keystatus then liftIO (doesFileExist obj) else inAnnex key u <- getUUID {- Since we're checking that a key's object file is present, throw - in a permission fixup here too. -}- when (present && not direct) $ do+ when present $ do void $ tryIO $ case keystatus of KeyUnlockedThin -> thawContent obj KeyLockedThin -> thawContent obj@@ -252,11 +248,7 @@ whenM (annexSecureHashesOnly <$> Annex.getGitConfig) $ warning $ "** Despite annex.securehashesonly being set, " ++ obj ++ " has content present in the annex using an insecure " ++ decodeBS (formatKeyVariety (keyVariety key)) ++ " key" - {- In direct mode, modified files will show up as not present,- - but that is expected and not something to do anything about. -}- if direct && not present- then return True- else verifyLocationLog' key ai present u (logChange key u)+ verifyLocationLog' key ai present u (logChange key u) verifyLocationLogRemote :: Key -> ActionItem -> Remote -> Bool -> Annex Bool verifyLocationLogRemote key ai remote present =@@ -319,56 +311,38 @@ {- Verifies the associated file records. -} verifyAssociatedFiles :: Key -> KeyStatus -> FilePath -> Annex Bool verifyAssociatedFiles key keystatus file = do- ifM isDirect (godirect, goindirect)- return True- where- godirect = do- fs <- Direct.addAssociatedFile key file- forM_ fs $ \f -> - unlessM (liftIO $ doesFileExist f) $- void $ Direct.removeAssociatedFile key f- goindirect = when (isKeyUnlockedThin keystatus) $ do+ when (isKeyUnlockedThin keystatus) $ do f <- inRepo $ toTopFilePath file afs <- Database.Keys.getAssociatedFiles key unless (getTopFilePath f `elem` map getTopFilePath afs) $ Database.Keys.addAssociatedFile key f+ return True verifyWorkTree :: Key -> FilePath -> Annex Bool verifyWorkTree key file = do- ifM isDirect ( godirect, goindirect )- return True- where- {- Ensures that files whose content is available are in direct mode. -}- godirect = whenM (isJust <$> isAnnexLink file) $ do- v <- toDirectGen key file- case v of- Nothing -> noop- Just a -> do- showNote "fixing direct mode"- a {- Make sure that a pointer file is replaced with its content, - when the content is available. -}- goindirect = do- mk <- liftIO $ isPointerFile file- case mk of- Just k | k == key -> whenM (inAnnex key) $ do- showNote "fixing worktree content"- replaceFile file $ \tmp -> do- mode <- liftIO $ catchMaybeIO $ fileMode <$> getFileStatus file- ifM (annexThin <$> Annex.getGitConfig)- ( void $ linkFromAnnex key tmp mode- , do- obj <- calcRepo $ gitAnnexLocation key- void $ checkedCopyFile key obj tmp mode- thawContent tmp- )- Database.Keys.storeInodeCaches key [file]- _ -> return ()+ mk <- liftIO $ isPointerFile file+ case mk of+ Just k | k == key -> whenM (inAnnex key) $ do+ showNote "fixing worktree content"+ replaceFile file $ \tmp -> do+ mode <- liftIO $ catchMaybeIO $ fileMode <$> getFileStatus file+ ifM (annexThin <$> Annex.getGitConfig)+ ( void $ linkFromAnnex key tmp mode+ , do+ obj <- calcRepo $ gitAnnexLocation key+ void $ checkedCopyFile key obj tmp mode+ thawContent tmp+ )+ Database.Keys.storeInodeCaches key [file]+ _ -> return ()+ return True {- The size of the data for a key is checked against the size encoded in - the key's metadata, if available. -- - Not checked when a file is unlocked, or in direct mode.+ - Not checked when a file is unlocked. -} checkKeySize :: Key -> KeyStatus -> ActionItem -> Annex Bool checkKeySize _ KeyUnlockedThin _ = return True@@ -439,28 +413,15 @@ - thus when the user modifies the file, the object will be modified and - not pass the check, and we don't want to find an error in this case. - So, skip the check if the key is unlocked and modified.- -- - In direct mode this is not done if the file has clearly been modified,- - because modification of direct mode files is allowed. It's still done- - if the file does not appear modified, to catch disk corruption, etc. -} checkBackend :: Backend -> Key -> KeyStatus -> AssociatedFile -> Annex Bool-checkBackend backend key keystatus afile = go =<< isDirect- where- go False = do- content <- calcRepo $ gitAnnexLocation key- ifM (pure (isKeyUnlockedThin keystatus) <&&> (not <$> isUnmodified key content))- ( nocheck- , checkBackendOr badContent backend key content ai- )- go True = case afile of- AssociatedFile Nothing -> nocheck- AssociatedFile (Just f) -> checkdirect f- checkdirect file = ifM (Direct.goodContent key file)- ( checkBackendOr' (badContentDirect file) backend key file ai- (Direct.goodContent key file)- , nocheck+checkBackend backend key keystatus afile = do+ content <- calcRepo $ gitAnnexLocation key+ ifM (pure (isKeyUnlockedThin keystatus) <&&> (not <$> isUnmodified key content))+ ( nocheck+ , checkBackendOr badContent backend key content ai )+ where nocheck = return True ai = mkActionItem (key, afile)@@ -475,7 +436,7 @@ -- The postcheck action is run after the content is verified, -- in order to detect situations where the file is changed while being--- verified (particularly in direct mode).+-- verified. checkBackendOr' :: (Key -> Annex String) -> Backend -> Key -> FilePath -> ActionItem -> Annex Bool -> Annex Bool checkBackendOr' bad backend key file ai postcheck = case Types.Backend.verifyKeyContent backend of@@ -546,14 +507,6 @@ dest <- moveBad key return $ "moved to " ++ dest -{- Bad content is left where it is, but we touch the file, so it'll be- - committed to a new key. -}-badContentDirect :: FilePath -> Key -> Annex String-badContentDirect file key = do- void $ liftIO $ catchMaybeIO $ touchFile file- logStatus key InfoMissing- return "left in place for you to examine"- {- Bad content is dropped from the remote. We have downloaded a copy - from the remote to a temp file already (in some cases, it's just a - symlink to a file in the remote). To avoid any further data loss,@@ -714,16 +667,13 @@ isKeyUnlockedThin KeyMissing = False getKeyStatus :: Key -> Annex KeyStatus-getKeyStatus key = ifM isDirect- ( return KeyUnlockedThin- , catchDefaultIO KeyMissing $ do- afs <- not . null <$> Database.Keys.getAssociatedFiles key- obj <- calcRepo $ gitAnnexLocation key- multilink <- ((> 1) . linkCount <$> liftIO (getFileStatus obj))- return $ if multilink && afs- then KeyUnlockedThin- else KeyPresent- )+getKeyStatus key = catchDefaultIO KeyMissing $ do+ afs <- not . null <$> Database.Keys.getAssociatedFiles key+ obj <- calcRepo $ gitAnnexLocation key+ multilink <- ((> 1) . linkCount <$> liftIO (getFileStatus obj))+ return $ if multilink && afs+ then KeyUnlockedThin+ else KeyPresent getKeyFileStatus :: Key -> FilePath -> Annex KeyStatus getKeyFileStatus key file = do
Command/FuzzTest.hs view
@@ -155,7 +155,6 @@ = FuzzAdd FuzzFile | FuzzDelete FuzzFile | FuzzMove FuzzFile FuzzFile- | FuzzModify FuzzFile | FuzzDeleteDir FuzzDir | FuzzMoveDir FuzzDir FuzzDir | FuzzPause Delay@@ -166,7 +165,6 @@ [ (50, FuzzAdd <$> arbitrary) , (50, FuzzDelete <$> arbitrary) , (10, FuzzMove <$> arbitrary <*> arbitrary)- , (10, FuzzModify <$> arbitrary) , (10, FuzzDeleteDir <$> arbitrary) , (10, FuzzMoveDir <$> arbitrary <*> arbitrary) , (10, FuzzPause <$> arbitrary)@@ -180,9 +178,6 @@ runFuzzAction (FuzzDelete (FuzzFile f)) = liftIO $ nukeFile f runFuzzAction (FuzzMove (FuzzFile src) (FuzzFile dest)) = liftIO $ rename src dest-runFuzzAction (FuzzModify (FuzzFile f)) = whenM isDirect $ liftIO $ do- n <- getStdRandom random :: IO Int- appendFile f $ show n ++ "\n" runFuzzAction (FuzzDeleteDir (FuzzDir d)) = liftIO $ removeDirectoryRecursive d runFuzzAction (FuzzMoveDir (FuzzDir src) (FuzzDir dest)) = liftIO $@@ -216,9 +211,6 @@ FuzzDeleteDir _ -> do d <- liftIO existingDir maybe genFuzzAction (return . FuzzDeleteDir) d- FuzzModify _ -> do- f <- liftIO $ existingFile 0 ""- maybe genFuzzAction (return . FuzzModify) f FuzzPause _ -> return tmpl existingFile :: Int -> FilePath -> IO (Maybe FuzzFile)
Command/Indirect.hs view
@@ -8,89 +8,14 @@ module Command.Indirect where import Command-import qualified Git-import qualified Git.Branch-import qualified Git.LsFiles-import Git.FileMode-import Config-import qualified Annex-import Annex.Direct-import Annex.Content-import Annex.Content.Direct-import Annex.CatFile-import Annex.Init-import Annex.Ingest cmd :: Command cmd = notBareRepo $ noDaemonRunning $- command "indirect" SectionSetup "switch repository to indirect mode"+ command "indirect" SectionSetup "switch repository to indirect mode (deprecated)" paramNothing (withParams seek) seek :: CmdParams -> CommandSeek seek = withNothing (commandAction start) start :: CommandStart-start = ifM isDirect- ( do- unlessM (coreSymlinks <$> Annex.getGitConfig) $- giveup "Git is configured to not use symlinks, so you must use direct mode."- whenM probeCrippledFileSystem $- giveup "This repository seems to be on a crippled filesystem, you must use direct mode."- starting "indirect" (ActionItemOther Nothing) - perform- , stop- )--perform :: CommandPerform-perform = do- whenM stageDirect $ do- showOutput- void $ inRepo $ Git.Branch.commitCommand Git.Branch.ManualCommit- [ Param "-m"- , Param "commit before switching to indirect mode"- ]-- -- Note that we set indirect mode early, so that we can use- -- moveAnnex in indirect mode.- setDirect False-- top <- fromRepo Git.repoPath- (l, clean) <- inRepo $ Git.LsFiles.stagedOthersDetails [top]- forM_ l go- void $ liftIO clean- next $ return True- where- {- Walk tree from top and move all present direct mode files into- - the annex, replacing with symlinks. Also delete direct mode- - caches and mappings. -}- go (f, Just sha, Just mode) | isSymLink mode = do- r <- liftIO $ catchMaybeIO $ getSymbolicLinkStatus f- case r of- Just s- | isSymbolicLink s -> void $ flip whenAnnexed f $- \_ k -> do- removeInodeCache k- removeAssociatedFiles k- return Nothing- | otherwise -> - maybe noop (fromdirect f)- =<< catKey sha- _ -> noop- go _ = noop-- fromdirect f k = do- removeInodeCache k- removeAssociatedFiles k- whenM (liftIO $ not . isSymbolicLink <$> getSymbolicLinkStatus f) $ do- v <- tryNonAsync (moveAnnex k f)- case v of- Right True -> do - l <- calcRepo $ gitAnnexLink f k- liftIO $ createSymbolicLink l f- Right False -> warnlocked "Failed to move file to annex"- Left e -> catchNonAsync (restoreFile f k e) $- warnlocked . show-- warnlocked msg = do- warning msg- warning "leaving this file as-is; correct this problem and run git annex add on it"+start = stop
Command/Info.hs view
@@ -31,7 +31,6 @@ import Logs.Location import Annex.NumCopies import Remote-import Config import Git.Config (boolConfig) import qualified Git.LsTree as LsTree import Utility.Percentage@@ -132,6 +131,7 @@ globalInfo :: InfoOptions -> Annex () globalInfo o = do+ disallowMatchingOptions u <- getUUID whenM ((==) DeadTrusted <$> lookupTrust u) $ earlyWarning "Warning: This repository is currently marked as dead."@@ -144,6 +144,7 @@ itemInfo o p = ifM (isdir p) ( dirInfo o p , do+ disallowMatchingOptions v <- Remote.byName' p case v of Right r -> remoteInfo o r@@ -164,6 +165,10 @@ showNote $ "not a directory or an annexed file or a treeish or a remote or a uuid" showEndFail +disallowMatchingOptions :: Annex ()+disallowMatchingOptions = whenM Limit.limited $+ giveup "File matching options can only be used when getting info on a directory."+ dirInfo :: InfoOptions -> FilePath -> Annex () dirInfo o dir = showCustom (unwords ["info", dir]) $ do stats <- selStats@@ -221,8 +226,7 @@ -} global_fast_stats :: [Stat] global_fast_stats = - [ repository_mode- , repo_list Trusted+ [ repo_list Trusted , repo_list SemiTrusted , repo_list UnTrusted , transfer_list@@ -267,7 +271,6 @@ remote_fast_stats :: Remote -> [Stat] remote_fast_stats r = map (\s -> s r) [ remote_name- , remote_trust , remote_cost , remote_type ]@@ -276,6 +279,7 @@ uuid_fast_stats u = map (\s -> s u) [ repo_uuid , repo_description+ , repo_trust ] uuid_slow_stats :: UUID -> [Stat]@@ -310,16 +314,6 @@ (lift . showHeader) desc lift . showRaw =<< a -repository_mode :: Stat-repository_mode = simpleStat "repository mode" $ lift $- ifM isDirect - ( return "direct"- , ifM (fromRepo Git.repoIsLocalBare)- ( return "bare"- , return "indirect"- )- )- repo_list :: TrustLevel -> Stat repo_list level = stat n $ nojson $ lift $ do us <- filter (/= NoUUID) . M.keys @@ -353,9 +347,8 @@ repo_uuid :: UUID -> Stat repo_uuid = simpleStat "uuid" . pure . fromUUID -remote_trust :: Remote -> Stat-remote_trust r = simpleStat "trust" $ lift $- showTrustLevel <$> lookupTrust (Remote.uuid r)+repo_trust :: UUID -> Stat+repo_trust u = simpleStat "trust" $ lift $ showTrustLevel <$> lookupTrust u remote_cost :: Remote -> Stat remote_cost r = simpleStat "cost" $ pure $@@ -525,7 +518,7 @@ case presentData s of Just v -> return v Nothing -> do- v <- foldKeys <$> lift (getKeysPresent InRepository)+ v <- foldKeys <$> lift (listKeys InAnnex) put s { presentData = Just v } return v
Command/Lock.hs view
@@ -10,7 +10,6 @@ import Command import qualified Annex.Queue import qualified Annex-import Annex.Version import Annex.Content import Annex.Link import Annex.InodeSentinal@@ -23,7 +22,7 @@ import Git.FilePath cmd :: Command-cmd = notDirect $ withGlobalOptions [jsonOptions, annexedMatchingOptions] $+cmd = withGlobalOptions [jsonOptions, annexedMatchingOptions] $ command "lock" SectionCommon "undo unlock command" paramPaths (withParams seek)@@ -31,12 +30,7 @@ seek :: CmdParams -> CommandSeek seek ps = do l <- workTreeItems ps- ifM versionSupportsUnlockedPointers- ( withFilesInGit (commandAction . (whenAnnexed startNew)) l- , do- withFilesOldUnlocked (commandAction . startOld) l- withFilesOldUnlockedToBeCommitted (commandAction . startOld) l- )+ withFilesInGit (commandAction . (whenAnnexed startNew)) l startNew :: FilePath -> Key -> CommandStart startNew file key = ifM (isJust <$> isAnnexLink file)
Command/Migrate.hs view
@@ -20,7 +20,7 @@ import Utility.Metered cmd :: Command-cmd = notDirect $ withGlobalOptions [annexedMatchingOptions] $+cmd = withGlobalOptions [annexedMatchingOptions] $ command "migrate" SectionUtility "switch data to different backend" paramPaths (withParams seek)
Command/Multicast.hs view
@@ -27,7 +27,6 @@ import Utility.Tmp import Utility.Tmp.Dir import Utility.Process.Transcript-import Config import Data.Char import qualified Data.ByteString.Lazy.UTF8 as B8@@ -128,8 +127,6 @@ -- In a direct mode repository, the annex objects do not have -- the names of keys, and would have to be copied, which is too -- expensive.- whenM isDirect $- giveup "Sorry, multicast send cannot be done from a direct mode repository." starting "sending files" (ActionItemOther Nothing) $ withTmpFile "send" $ \t h -> do fs' <- seekHelper LsFiles.inRepo =<< workTreeItems fs@@ -140,7 +137,7 @@ mk <- lookupFile f case mk of Nothing -> noop- Just k -> withObjectLoc k (addlist f) (const noop)+ Just k -> withObjectLoc k (addlist f) liftIO $ hClose h serverkey <- uftpKey
Command/PreCommit.hs view
@@ -10,23 +10,17 @@ module Command.PreCommit where import Command-import Config-import qualified Command.Add import qualified Command.Fix import qualified Command.Smudge-import Annex.Direct import Annex.Hook import Annex.Link import Annex.View-import Annex.Version import Annex.View.ViewedFile import Annex.LockFile import Logs.View import Logs.MetaData import Types.View import Types.MetaData-import qualified Git.Index as Git-import qualified Git.LsFiles as Git import qualified Data.Set as S import qualified Data.Text as T@@ -38,60 +32,25 @@ (withParams seek) seek :: CmdParams -> CommandSeek-seek ps = lockPreCommitHook $ ifM isDirect- ( do- -- update direct mode mappings for committed files- withWords (commandAction . startDirect) ps- runAnnexHook preCommitAnnexHook- , do- ifM (not <$> versionSupportsUnlockedPointers <&&> liftIO Git.haveFalseIndex)- ( do- (fs, cleanup) <- inRepo $ Git.typeChangedStaged ps- whenM (anyM isOldUnlocked fs) $- giveup "Cannot make a partial commit with unlocked annexed files. You should `git annex add` the files you want to commit, and then run git commit."- void $ liftIO cleanup- , do- l <- workTreeItems ps- -- fix symlinks to files being committed- flip withFilesToBeCommitted l $ \f -> commandAction $- maybe stop (Command.Fix.start Command.Fix.FixSymlinks f)- =<< isAnnexLink f- ifM versionSupportsUnlockedPointers- -- after a merge conflict or git- -- cherry-pick or stash, pointer- -- files in the worktree won't- -- be populated, so populate them- -- here- ( Command.Smudge.updateSmudged - -- When there's a false index,- -- restaging the files won't work.- . Restage =<< liftIO Git.haveFalseIndex- -- inject unlocked files into the annex- -- (not needed when repo version uses- -- unlocked pointer files)- , withFilesOldUnlockedToBeCommitted (commandAction . startInjectUnlocked) l- )- )- runAnnexHook preCommitAnnexHook- -- committing changes to a view updates metadata- mv <- currentView- case mv of- Nothing -> noop- Just v -> withViewChanges- (addViewMetaData v)- (removeViewMetaData v)- )+seek ps = lockPreCommitHook $ do+ l <- workTreeItems ps+ -- fix symlinks to files being committed+ flip withFilesToBeCommitted l $ \f -> commandAction $+ maybe stop (Command.Fix.start Command.Fix.FixSymlinks f)+ =<< isAnnexLink f+ -- after a merge conflict or git cherry-pick or stash, pointer+ -- files in the worktree won't be populated, so populate them here+ Command.Smudge.updateSmudged (Restage False) --startInjectUnlocked :: FilePath -> CommandStart-startInjectUnlocked f = startingCustomOutput (ActionItemOther Nothing) $ do- unlessM (callCommandAction $ Command.Add.start f) $- error $ "failed to add " ++ f ++ "; canceling commit"- next $ return True+ runAnnexHook preCommitAnnexHook -startDirect :: [String] -> CommandStart-startDirect _ = startingCustomOutput (ActionItemOther Nothing) $ - next preCommitDirect+ -- committing changes to a view updates metadata+ mv <- currentView+ case mv of+ Nothing -> noop+ Just v -> withViewChanges+ (addViewMetaData v)+ (removeViewMetaData v) addViewMetaData :: View -> ViewedFile -> Key -> CommandStart addViewMetaData v f k = starting "metadata" (mkActionItem (k, f)) $
Command/Proxy.hs view
@@ -8,23 +8,11 @@ module Command.Proxy where import Command-import Config-import Utility.Tmp.Dir-import Utility.Env-import Annex.Direct-import Annex.Tmp-import qualified Git-import qualified Git.Sha-import qualified Git.Ref-import qualified Git.Branch-import qualified Git.LsFiles-import Git.FilePath-import Utility.CopyFile cmd :: Command cmd = notBareRepo $ command "proxy" SectionPlumbing - "safely bypass direct mode guard"+ "safely bypass direct mode guard (deprecated)" ("-- git command") (withParams seek) seek :: CmdParams -> CommandSeek@@ -32,48 +20,4 @@ start :: [String] -> CommandStart start [] = giveup "Did not specify command to run."-start (c:ps) = liftIO . exitWith =<< ifM isDirect- ( withOtherTmp $ \tmp -> withTmpDirIn tmp "proxy" go- , liftIO $ safeSystem c (map Param ps)- )- where- go tmp = do- oldref <- fromMaybe Git.Sha.emptyTree- <$> (inRepo . maybe Git.Ref.headSha Git.Ref.sha- =<< inRepo Git.Branch.currentUnsafe)- - exitcode <- proxy tmp-- cleanupproxy tmp oldref-- return exitcode- - proxy tmp = do- usetmp <- liftIO $ Just . addEntry "GIT_WORK_TREE" tmp <$> getEnvironment-- -- Set up the tmp work tree, to contain both a checkout of all- -- staged files as well as hard links (or copies) of any- -- unstaged files.- unlessM (isNothing <$> inRepo Git.Branch.current) $- unlessM (liftIO $ boolSystemEnv "git" [Param "checkout", Param "--", Param "."] usetmp) $- error "Failed to set up proxy work tree."- top <- fromRepo Git.repoPath- (fs, cleanup) <- inRepo $ Git.LsFiles.notInRepo True [top]- forM_ fs $ \f -> do- tf <- inRepo $ toTopFilePath f- let tmpf = tmp </> getTopFilePath tf- liftIO $ do- createDirectoryIfMissing True (takeDirectory tmpf)- createLinkOrCopy f tmpf- liftIO $ void cleanup-- liftIO $ safeSystemEnv c (map Param ps) usetmp- - -- To merge the changes made by the proxied command into- -- the work tree is similar to cleaning up after a- -- direct mode merge. But, here we force updates of any- -- non-annxed files that were changed by the proxied- -- command.- cleanupproxy tmp oldref = do- updateWorkTree tmp oldref True- liftIO $ removeDirectoryRecursive tmp+start (c:ps) = liftIO $ exitWith =<< safeSystem c (map Param ps)
Command/ReKey.hs view
@@ -21,11 +21,10 @@ import Utility.InodeCache cmd :: Command-cmd = notDirect $ - command "rekey" SectionPlumbing- "change keys used for files"- (paramRepeating $ paramPair paramPath paramKey)- (seek <$$> optParser)+cmd = command "rekey" SectionPlumbing+ "change keys used for files"+ (paramRepeating $ paramPair paramPath paramKey)+ (seek <$$> optParser) data ReKeyOptions = ReKeyOptions { reKeyThese :: CmdParams
Command/RegisterUrl.hs view
@@ -15,7 +15,7 @@ import qualified Remote cmd :: Command-cmd = notDirect $ notBareRepo $+cmd = notBareRepo $ command "registerurl" SectionPlumbing "registers an url for a key" (paramPair paramKey paramUrl)
Command/Status.hs view
@@ -8,11 +8,7 @@ module Command.Status where import Command-import Annex.CatFile-import Annex.Content.Direct-import Config import Git.Status-import qualified Git.Ref import Git.FilePath cmd :: Command@@ -42,10 +38,7 @@ start :: StatusOptions -> [FilePath] -> CommandStart start o locs = do (l, cleanup) <- inRepo $ getStatus ps locs- getstatus <- ifM isDirect- ( return (maybe (pure Nothing) statusDirect . simplifiedStatus)- , return (pure . simplifiedStatus)- )+ let getstatus = pure . simplifiedStatus forM_ l $ \s -> maybe noop displayStatus =<< getstatus s ifM (liftIO cleanup) ( stop@@ -71,38 +64,3 @@ f <- liftIO $ relPathCwdToFile absf unlessM (showFullJSON $ JSONChunk [("status", [c]), ("file", f)]) $ liftIO $ putStrLn $ [c] ++ " " ++ f---- Git thinks that present direct mode files are typechanged.--- (On crippled filesystems, git instead thinks they're modified.)--- Check their content to see if they are modified or not.-statusDirect :: Status -> Annex (Maybe Status)-statusDirect (TypeChanged t) = statusDirect' t-statusDirect s@(Modified t) = ifM crippledFileSystem- ( statusDirect' t- , pure (Just s)- )-statusDirect s = pure (Just s)--statusDirect' :: TopFilePath -> Annex (Maybe Status)-statusDirect' t = do- absf <- fromRepo $ fromTopFilePath t- f <- liftIO $ relPathCwdToFile absf- v <- liftIO (catchMaybeIO $ getFileStatus f)- case v of- Nothing -> return $ Just $ Deleted t- Just s- | not (isSymbolicLink s) ->- checkkey f s =<< catKeyFile f- | otherwise -> Just <$> checkNew f t- where- checkkey f s (Just k) = ifM (sameFileStatus k f s)- ( return Nothing- , return $ Just $ Modified t- )- checkkey f _ Nothing = Just <$> checkNew f t--checkNew :: FilePath -> TopFilePath -> Annex Status-checkNew f t = ifM (isJust <$> catObjectDetails (Git.Ref.fileRef f))- ( return (Modified t)- , return (Untracked t)- )
Command/Sync.hs view
@@ -30,7 +30,6 @@ import qualified Annex.Branch import qualified Remote import qualified Types.Remote as Remote-import Annex.Direct import Annex.Hook import qualified Git.Command import qualified Git.LsFiles as LsFiles@@ -250,7 +249,7 @@ ResolveMergeOverride False -> return False syncBranch :: Git.Branch -> Git.Branch-syncBranch = Git.Ref.underBase "refs/heads/synced" . fromDirectBranch . fromAdjustedBranch+syncBranch = Git.Ref.underBase "refs/heads/synced" . fromAdjustedBranch remoteBranch :: Remote -> Git.Ref -> Git.Ref remoteBranch remote = Git.Ref.underBase $ "refs/remotes/" ++ Remote.name remote@@ -286,20 +285,14 @@ commit o = stopUnless shouldcommit $ starting "commit" (ActionItemOther Nothing) $ do commitmessage <- maybe commitMsg return (messageOption o) Annex.Branch.commit =<< Annex.Branch.commitMessage- next $ ifM isDirect- ( do- void stageDirect- void preCommitDirect- commitStaged Git.Branch.ManualCommit commitmessage- , do- showOutput- void $ inRepo $ Git.Branch.commitCommand Git.Branch.ManualCommit- [ Param "-a"- , Param "-m"- , Param commitmessage- ]- return True- )+ next $ do+ showOutput+ void $ inRepo $ Git.Branch.commitCommand Git.Branch.ManualCommit+ [ Param "-a"+ , Param "-m"+ , Param commitmessage+ ]+ return True where shouldcommit = pure (commitOption o) <||> (pure (not (noCommitOption o)) <&&> getGitConfigVal annexAutoCommit)@@ -378,12 +371,6 @@ -- Update the sync branch to match the new state of the branch inRepo $ updateBranch (syncBranch branch) branch - -- In direct mode, we're operating on some special direct mode- -- branch, rather than the intended branch, so update the intended- -- branch.- whenM isDirect $- inRepo $ updateBranch (fromDirectBranch branch) branch- updateBranch :: Git.Branch -> Git.Branch -> Git.Repo -> IO () updateBranch syncbranch updateto g = unlessM go $ giveup $ "failed to update " ++ Git.fromRef syncbranch@@ -449,7 +436,7 @@ (mapM (merge currbranch mergeconfig resolvemergeoverride Git.Branch.ManualCommit . remoteBranch remote) =<< getlist) tomerge = filterM (changed remote) branchlist Nothing = []- branchlist (Just branch) = [fromDirectBranch (fromAdjustedBranch branch), syncBranch branch]+ branchlist (Just branch) = [fromAdjustedBranch branch, syncBranch branch] pushRemote :: SyncOptions -> Remote -> CurrBranch -> CommandStart pushRemote _o _remote (Nothing, _) = stop@@ -471,8 +458,9 @@ | remoteAnnexReadOnly gc = return False | not (remoteAnnexPush gc) = return False | otherwise = anyM (newer remote) [syncBranch branch, Annex.Branch.name]- -- Do updateInstead emulation for remotes on eg removable drives- -- formatted FAT, where the post-receive hook won't run.+ -- Older remotes on crippled filesystems may not have a+ -- post-receive hook set up, so when updateInstead emulation+ -- is needed, run post-receive manually. postpushupdate repo = case Git.repoWorkTree repo of Nothing -> return True Just wt -> ifM needemulation@@ -540,7 +528,7 @@ -- receive.denyCurrentBranch=updateInstead -- the user -- will want to see that one. let p = flip Git.Command.gitCreateProcess g $ pushparams- [ Git.fromRef $ Git.Ref.base $ fromDirectBranch $ fromAdjustedBranch branch ]+ [ Git.fromRef $ Git.Ref.base $ fromAdjustedBranch branch ] (transcript, ok) <- processTranscript' p Nothing when (not ok && not ("denyCurrentBranch" `isInfixOf` transcript)) $ hPutStr stderr transcript
Command/Unannex.hs view
@@ -8,18 +8,11 @@ module Command.Unannex where import Command-import Config import qualified Annex import Annex.Content import Annex.Perms-import Annex.Content.Direct-import Annex.Version import qualified Git.Command-import qualified Git.Branch-import qualified Git.Ref-import qualified Git.DiffTree as DiffTree import Utility.CopyFile-import Command.PreCommit (lockPreCommitHook) import qualified Database.Keys import Git.FilePath @@ -30,51 +23,15 @@ paramPaths (withParams seek) seek :: CmdParams -> CommandSeek-seek ps = wrapUnannex $ - (withFilesInGit $ commandAction . whenAnnexed start) =<< workTreeItems ps--wrapUnannex :: Annex a -> Annex a-wrapUnannex a = ifM (versionSupportsUnlockedPointers <||> isDirect)- ( a- {- Run with the pre-commit hook disabled, to avoid confusing- - behavior if an unannexed file is added back to git as- - a normal, non-annexed file and then committed.- - Otherwise, the pre-commit hook would think that the file- - has been unlocked and needs to be re-annexed.- -- - At the end, make a commit removing the unannexed files.- -}- , ifM cleanindex- ( lockPreCommitHook $ commit `after` a- , giveup "Cannot proceed with uncommitted changes staged in the index. Recommend you: git commit"- )- )- where- commit = inRepo $ Git.Branch.commitCommand Git.Branch.ManualCommit- [ Param "-q"- , Param "--allow-empty"- , Param "--no-verify"- , Param "-m", Param "content removed from git annex"- ]- cleanindex = ifM (inRepo Git.Ref.headExists)- ( do- (diff, cleanup) <- inRepo $ DiffTree.diffIndex Git.Ref.headRef- if null diff- then void (liftIO cleanup) >> return True- else void (liftIO cleanup) >> return False- , return False- )+seek ps = (withFilesInGit $ commandAction . whenAnnexed start) =<< workTreeItems ps start :: FilePath -> Key -> CommandStart start file key = stopUnless (inAnnex key) $ starting "unannex" (mkActionItem (key, file)) $- ifM isDirect- ( performDirect file key- , performIndirect file key- )+ perform file key -performIndirect :: FilePath -> Key -> CommandPerform-performIndirect file key = do+perform :: FilePath -> Key -> CommandPerform+perform file key = do liftIO $ removeFile file inRepo $ Git.Command.run [ Param "rm"@@ -84,10 +41,10 @@ , Param "--" , File file ]- next $ cleanupIndirect file key+ next $ cleanup file key -cleanupIndirect :: FilePath -> Key -> CommandCleanup-cleanupIndirect file key = do+cleanup :: FilePath -> Key -> CommandCleanup+cleanup file key = do Database.Keys.removeAssociatedFile key =<< inRepo (toTopFilePath file) src <- calcRepo $ gitAnnexLocation key ifM (Annex.getState Annex.fast)@@ -112,28 +69,3 @@ ( return True , copyfrom src )--performDirect :: FilePath -> Key -> CommandPerform-performDirect file key = do- -- --force is needed when the file is not committed- inRepo $ Git.Command.run- [ Param "rm"- , Param "--cached"- , Param "--force"- , Param "--quiet"- , Param "--"- , File file- ]- next $ cleanupDirect file key--{- The direct mode file is not touched during unannex, so the content- - is already where it needs to be, so this does not need to do anything- - except remove it from the associated file map (which also updates- - the location log if this was the last copy), and, if this was the last- - associated file, remove the inode cache. -}-cleanupDirect :: FilePath -> Key -> CommandCleanup-cleanupDirect file key = do- fs <- removeAssociatedFile key file- when (null fs) $- removeInodeCache key- return True
Command/Undo.hs view
@@ -8,9 +8,6 @@ module Command.Undo where import Command-import Config-import Annex.Direct-import Annex.CatFile import Git.DiffTree import Git.FilePath import Git.UpdateIndex@@ -37,9 +34,7 @@ -- Committing staged changes before undo allows later -- undoing the undo. It would be nicer to only commit staged- -- changes to the specified files, rather than all staged changes,- -- but that is difficult to do; a partial git-commit can't be done - -- in direct mode.+ -- changes to the specified files, rather than all staged changes. void $ Command.Sync.commitStaged Git.Branch.ManualCommit "commit before undo" @@ -68,16 +63,10 @@ forM_ removals $ \di -> do f <- mkrel di- whenM isDirect $- maybe noop (`removeDirect` f)- =<< catKey (srcsha di) liftIO $ nukeFile f forM_ adds $ \di -> do f <- mkrel di inRepo $ Git.run [Param "checkout", Param "--", File f]- whenM isDirect $- maybe noop (`toDirect` f)- =<< catKey (dstsha di) next $ liftIO cleanup
Command/Uninit.hs view
@@ -59,7 +59,7 @@ finish = do annexdir <- fromRepo gitAnnexDir annexobjectdir <- fromRepo gitAnnexObjectDir- leftovers <- removeUnannexed =<< getKeysPresent InAnnex+ leftovers <- removeUnannexed =<< listKeys InAnnex prepareRemoveAnnexDir annexdir if null leftovers then liftIO $ removeDirectoryRecursive annexdir
Command/Unlock.hs view
@@ -10,11 +10,8 @@ import Command import Annex.Content import Annex.Perms-import Annex.CatFile-import Annex.Version import Annex.Link import Annex.ReplaceFile-import Utility.CopyFile import Git.FilePath import qualified Database.Keys @@ -25,9 +22,8 @@ editcmd = mkcmd "edit" "same as unlock" mkcmd :: String -> String -> Command-mkcmd n d = notDirect $ - withGlobalOptions [jsonOptions, annexedMatchingOptions] $- command n SectionCommon d paramPaths (withParams seek)+mkcmd n d = withGlobalOptions [jsonOptions, annexedMatchingOptions] $+ command n SectionCommon d paramPaths (withParams seek) seek :: CmdParams -> CommandSeek seek ps = withFilesInGit (commandAction . whenAnnexed start) =<< workTreeItems ps@@ -38,15 +34,12 @@ start :: FilePath -> Key -> CommandStart start file key = ifM (isJust <$> isAnnexLink file) ( starting "unlock" (mkActionItem (key, AssociatedFile (Just file))) $- ifM versionSupportsUnlockedPointers- ( performNew file key- , performOld file key- )+ perform file key , stop ) -performNew :: FilePath -> Key -> CommandPerform-performNew dest key = do+perform :: FilePath -> Key -> CommandPerform+perform dest key = do destmode <- liftIO $ catchMaybeIO $ fileMode <$> getFileStatus dest replaceFile dest $ \tmp -> ifM (inAnnex key)@@ -58,47 +51,10 @@ LinkAnnexFailed -> error "unlock failed" , liftIO $ writePointerFile tmp key destmode )- next $ cleanupNew dest key destmode+ next $ cleanup dest key destmode -cleanupNew :: FilePath -> Key -> Maybe FileMode -> CommandCleanup-cleanupNew dest key destmode = do+cleanup :: FilePath -> Key -> Maybe FileMode -> CommandCleanup+cleanup dest key destmode = do stagePointerFile dest destmode =<< hashPointerFile key Database.Keys.addAssociatedFile key =<< inRepo (toTopFilePath dest) return True--performOld :: FilePath -> Key -> CommandPerform-performOld file key = - ifM (inAnnex key)- ( ifM (isJust <$> catKeyFileHEAD file)- ( performOld' file key- , do- warning "this has not yet been committed to git; cannot unlock it"- next $ return False- )- , do- warning "content not present; cannot unlock"- next $ return False- )--performOld' :: FilePath -> Key -> CommandPerform-performOld' dest key = ifM (checkDiskSpace Nothing key 0 True)- ( do- src <- calcRepo $ gitAnnexLocation key- tmpdest <- fromRepo $ gitAnnexTmpObjectLocation key- liftIO $ createDirectoryIfMissing True (parentDir tmpdest)- showAction "copying"- ifM (liftIO $ copyFileExternal CopyAllMetaData src tmpdest)- ( do- liftIO $ do- removeFile dest- moveFile tmpdest dest- thawContent dest- next $ return True- , do- warning "copy failed!"- next $ return False- )- , do- warning "not enough disk space to copy file"- next $ return False- )
Command/Unused.hs view
@@ -84,9 +84,7 @@ return [] findunused False = do showAction "checking for unused data"- -- InAnnex, not InRepository because if a direct mode- -- file exists, it is obviously not unused.- excludeReferenced refspec =<< getKeysPresent InAnnex+ excludeReferenced refspec =<< listKeys InAnnex chain _ [] = next $ return True chain v (a:as) = do v' <- a v
Command/Upgrade.hs view
@@ -13,9 +13,13 @@ import Annex.Init cmd :: Command-cmd = dontCheck repoExists $ -- because an old version may not seem to exist- noDaemonRunning $ -- avoid upgrading repo out from under daemon- command "upgrade" SectionMaintenance "upgrade repository layout"+cmd = dontCheck repoExists $+ -- ^ because an old version may not seem to exist+ -- and also, this avoids automatic silent upgrades before+ -- this command can start up.+ noDaemonRunning $+ -- ^ avoid upgrading repo out from under daemon+ command "upgrade" SectionMaintenance "upgrade repository" paramNothing (withParams seek) seek :: CmdParams -> CommandSeek
Command/VAdd.hs view
@@ -12,7 +12,7 @@ import Command.View (checkoutViewBranch) cmd :: Command-cmd = notBareRepo $ notDirect $+cmd = notBareRepo $ command "vadd" SectionMetaData "add subdirs to current view" (paramRepeating "FIELD=GLOB")
Command/VCycle.hs view
@@ -14,7 +14,7 @@ import Command.View (checkoutViewBranch) cmd :: Command-cmd = notBareRepo $ notDirect $+cmd = notBareRepo $ command "vcycle" SectionMetaData "switch view to next layout" paramNothing (withParams seek)
Command/VFilter.hs view
@@ -12,7 +12,7 @@ import Command.View (paramView, checkoutViewBranch) cmd :: Command-cmd = notBareRepo $ notDirect $+cmd = notBareRepo $ command "vfilter" SectionMetaData "filter current view" paramView (withParams seek)
Command/VPop.hs view
@@ -16,7 +16,7 @@ import Command.View (checkoutViewBranch) cmd :: Command-cmd = notBareRepo $ notDirect $+cmd = notBareRepo $ command "vpop" SectionMetaData "switch back to previous view" paramNumber (withParams seek)
Command/View.hs view
@@ -20,7 +20,7 @@ import Logs.View cmd :: Command-cmd = notBareRepo $ notDirect $+cmd = notBareRepo $ command "view" SectionMetaData "enter a view branch" paramView (withParams seek)
Database/Keys.hs view
@@ -29,7 +29,6 @@ import Database.Init import Annex.Locations import Annex.Common hiding (delete)-import Annex.Version (versionUsesKeysDatabase) import qualified Annex import Annex.LockFile import Annex.CatFile@@ -103,10 +102,7 @@ where go (Just h) = pure h go Nothing = do- h <- ifM versionUsesKeysDatabase- ( liftIO newDbHandle- , liftIO unavailableDbHandle- )+ h <- liftIO newDbHandle Annex.changeState $ \s -> s { Annex.keysdbhandle = Just h } return h @@ -220,7 +216,7 @@ - file. -} reconcileStaged :: H.DbQueue -> Annex ()-reconcileStaged qh = whenM versionUsesKeysDatabase $ do+reconcileStaged qh = do gitindex <- inRepo currentIndexFile indexcache <- fromRepo gitAnnexKeysDbIndexCache withTSDelta (liftIO . genInodeCache gitindex) >>= \case
Git/Branch.hs view
@@ -15,7 +15,6 @@ import Git.Command import qualified Git.Config import qualified Git.Ref-import qualified Git.BuildVersion {- The currently checked out branch. -@@ -125,8 +124,7 @@ {- Prevent signing automatic commits. -} applyCommitMode :: CommitMode -> [CommandParam] -> [CommandParam] applyCommitMode commitmode ps- | commitmode == AutomaticCommit && not (Git.BuildVersion.older "2.0.0") =- Param "--no-gpg-sign" : ps+ | commitmode == AutomaticCommit = Param "--no-gpg-sign" : ps | otherwise = ps {- Some versions of git commit-tree honor commit.gpgsign themselves,
Git/CheckAttr.hs view
@@ -10,12 +10,11 @@ import Common import Git import Git.Command-import qualified Git.Version import qualified Utility.CoProcess as CoProcess import System.IO.Error -type CheckAttrHandle = (CoProcess.CoProcessHandle, [Attr], Bool, String)+type CheckAttrHandle = (CoProcess.CoProcessHandle, [Attr], String) type Attr = String @@ -25,8 +24,7 @@ checkAttrStart attrs repo = do currdir <- getCurrentDirectory h <- gitCoProcessStart True params repo- oldgit <- Git.Version.older "1.7.7"- return (h, attrs, oldgit, currdir)+ return (h, attrs, currdir) where params = [ Param "check-attr" @@ -36,12 +34,12 @@ [ Param "--" ] checkAttrStop :: CheckAttrHandle -> IO ()-checkAttrStop (h, _, _, _) = CoProcess.stop h+checkAttrStop (h, _, _) = CoProcess.stop h {- Gets an attribute of a file. When the attribute is not specified, - returns "" -} checkAttr :: CheckAttrHandle -> Attr -> FilePath -> IO String-checkAttr (h, attrs, oldgit, currdir) want file = do+checkAttr (h, attrs, currdir) want file = do pairs <- CoProcess.query h send (receive "") let vals = map snd $ filter (\(attr, _) -> attr == want) pairs case vals of@@ -78,16 +76,9 @@ else Nothing -- line incomplete numattrs = length attrs - {- Before git 1.7.7, git check-attr worked best with- - absolute filenames; using them worked around some bugs- - with relative filenames.- - - - With newer git, git check-attr chokes on some absolute- - filenames, and the bugs that necessitated them were fixed,- - so use relative filenames. -}- file'- | oldgit = absPathFrom currdir file- | otherwise = relPathDirToFileAbs currdir $ absPathFrom currdir file+ {- git check-attr chokes on some absolute filenames,+ - so make sure the filename is relative. -}+ file' = relPathDirToFileAbs currdir $ absPathFrom currdir file oldattrvalue attr l = end bits !! 0 where bits = split sep l
Git/CheckIgnore.hs view
@@ -15,7 +15,6 @@ import Common import Git import Git.Command-import qualified Git.Version import qualified Utility.CoProcess as CoProcess import System.IO.Error@@ -29,17 +28,11 @@ - GIT_FLUSH behavior flushing the output buffer when git check-ignore - is piping to us. -- - The first version of git to support what we need is 1.8.4.- - Nothing is returned if an older git is installed.- - - check-ignore does not support --literal-pathspecs, so remove that - from the gitGlobalOpts if set. -}-checkIgnoreStart :: Repo -> IO (Maybe CheckIgnoreHandle)-checkIgnoreStart repo = ifM supportedGitVersion- ( Just <$> gitCoProcessStart True params repo'- , return Nothing- )+checkIgnoreStart :: Repo -> IO CheckIgnoreHandle+checkIgnoreStart repo = gitCoProcessStart True params repo' where params = [ Param "check-ignore" @@ -51,11 +44,6 @@ repo' = repo { gitGlobalOpts = filter (not . pathspecs) (gitGlobalOpts repo) } pathspecs (Param "--literal-pathspecs") = True pathspecs _ = False--supportedGitVersion :: IO Bool-supportedGitVersion = do- v <- Git.Version.installed- return $ v >= Git.Version.normalize "1.8.4" {- For some reason, check-ignore --batch always exits nonzero, - so ignore any error. -}
Git/Fsck.hs view
@@ -22,7 +22,6 @@ import Git.Command import Git.Sha import Utility.Batch-import qualified Git.Version import qualified Data.Set as S import Control.Concurrent.Async@@ -73,9 +72,7 @@ -} findBroken :: Bool -> Repo -> IO FsckResults findBroken batchmode r = do- supportsNoDangling <- (>= Git.Version.normalize "1.7.10")- <$> Git.Version.installed- let (command, params) = ("git", fsckParams supportsNoDangling r)+ let (command, params) = ("git", fsckParams r) (command', params') <- if batchmode then toBatchCommand (command, params) else return (command, params)@@ -86,8 +83,8 @@ , std_err = CreatePipe } (o1, o2) <- concurrently- (parseFsckOutput maxobjs r supportsNoDangling (stdoutHandle p))- (parseFsckOutput maxobjs r supportsNoDangling (stderrHandle p))+ (parseFsckOutput maxobjs r (stdoutHandle p))+ (parseFsckOutput maxobjs r (stderrHandle p)) fsckok <- checkSuccessProcess pid case mappend o1 o2 of FsckOutput badobjs truncated@@ -120,15 +117,15 @@ findMissing :: [Sha] -> Repo -> IO MissingObjects findMissing objs r = S.fromList <$> filterM (`isMissing` r) objs -parseFsckOutput :: Int -> Repo -> Bool -> Handle -> IO FsckOutput-parseFsckOutput maxobjs r supportsNoDangling h = do+parseFsckOutput :: Int -> Repo -> Handle -> IO FsckOutput+parseFsckOutput maxobjs r h = do ls <- lines <$> hGetContents h if null ls then return NoFsckOutput else if all ("duplicateEntries" `isInfixOf`) ls then return AllDuplicateEntriesWarning else do- let shas = findShas supportsNoDangling ls+ let shas = findShas ls let !truncated = length shas > maxobjs missingobjs <- findMissing (take maxobjs shas) r return $ FsckOutput missingobjs truncated@@ -141,18 +138,14 @@ , Param (fromRef s) ] r -findShas :: Bool -> [String] -> [Sha]-findShas supportsNoDangling = catMaybes . map extractSha . concat . map words . filter wanted+findShas :: [String] -> [Sha]+findShas = catMaybes . map extractSha . concat . map words . filter wanted where- wanted l- | supportsNoDangling = True- | otherwise = not ("dangling " `isPrefixOf` l)+ wanted l = not ("dangling " `isPrefixOf` l) -fsckParams :: Bool -> Repo -> [CommandParam]-fsckParams supportsNoDangling = gitCommandLine $ map Param $ catMaybes- [ Just "fsck"- , if supportsNoDangling- then Just "--no-dangling"- else Nothing- , Just "--no-reflogs"+fsckParams :: Repo -> [CommandParam]+fsckParams = gitCommandLine $ map Param+ [ "fsck"+ , "--no-dangling"+ , "--no-reflogs" ]
Git/Index.hs view
@@ -58,19 +58,3 @@ {- Git locks the index by creating this file. -} indexFileLock :: FilePath -> FilePath indexFileLock f = f ++ ".lock"--{- When the pre-commit hook is run, and git commit has been run with- - a file or files specified to commit, rather than committing the staged- - index, git provides the pre-commit hook with a "false index file".- -- - Changes made to this index will influence the commit, but won't- - affect the real index file.- -- - This detects when we're in this situation, using a heuristic, which- - might be broken by changes to git. Any use of this should have a test- - case to make sure it works.- -}-haveFalseIndex :: IO Bool-haveFalseIndex = maybe (False) check <$> getEnv indexEnv- where- check f = "next-index" `isPrefixOf` takeFileName f
Git/Merge.hs view
@@ -17,7 +17,6 @@ import Common import Git import Git.Command-import qualified Git.BuildVersion import qualified Git.Version import Git.Branch (CommitMode(..)) @@ -33,7 +32,7 @@ merge' :: [CommandParam] -> Ref -> [MergeConfig] -> CommitMode -> Repo -> IO Bool merge' extraparams branch mergeconfig commitmode r- | MergeNonInteractive `notElem` mergeconfig || Git.BuildVersion.older "1.7.7.6" =+ | MergeNonInteractive `notElem` mergeconfig = go [Param $ fromRef branch] | otherwise = go [Param "--no-edit", Param $ fromRef branch] where
Git/Remote/Remove.hs view
@@ -13,17 +13,10 @@ import Git import Git.Types import qualified Git.Command-import qualified Git.Version remove :: RemoteName -> Repo -> IO ()-remove remotename r = do- old <- Git.Version.older "1.8.0"- Git.Command.run- [ Param "remote"- -- name of this subcommand changed- , Param $- if old- then "rm"- else "remove"- , Param remotename- ] r+remove remotename = Git.Command.run+ [ Param "remote"+ , Param "remove"+ , Param remotename+ ]
NEWS view
@@ -1,3 +1,31 @@+git-annex (7.20190912) upstream; urgency=medium++ This version of git-annex uses repository version 7 for all repositories.++ Existing v5 repositories will be automatically upgraded by default.+ You can prevent this, by runing: git config annex.autoupgraderepository false++ A v7 repository can can have some files locked while other files are+ unlocked, and all git and git-annex commands can be used on both locked and+ unlocked files. It's a good idea to make sure that all users of the+ repository have upgraded git-annex and upgraded their repositories+ to the new version before starting to use that feature, since old+ versions of git-annex will ignore the new unlocked files.++ The behavior of some commands changes in an upgraded repository:+ + * `git add` will add files to the annex, rather than adding them directly+ to the git repository. To cause some files to be added directly+ to git, you can configure `annex.largefiles`. For example:++ git config annex.largefiles "largerthan=100kb and not (include=*.c or include=*.h)"++ * `git annex unlock` and `git annex lock` change how the pointer to + the annexed content is stored in git. If you commit the change,+ that will impact all clones of the repository.++ -- Joey Hess <id@joeyh.name> Fri, 13 Sep 2019 12:19:55 -0400+ git-annex (7.20181031) upstream; urgency=medium Repository version 7 is now available. v6 repositories will automatically
Remote/Git.hs view
@@ -37,13 +37,11 @@ import Config.Cost import Config.DynamicConfig import Annex.Init-import Annex.Version import Types.CleanupActions import qualified CmdLine.GitAnnexShell.Fields as Fields import Logs.Location import Utility.Metered import Utility.CopyFile-import Utility.FileMode import Utility.Env import Utility.Batch import Utility.SimpleProtocol@@ -62,6 +60,10 @@ import Annex.Action import Messages.Progress +#ifndef mingw32_HOST_OS+import Utility.FileMode+#endif+ import Control.Concurrent import Control.Concurrent.MSampleVar import qualified Data.Map as M@@ -324,7 +326,7 @@ readlocalannexconfig = do let check = do Annex.BranchState.disableUpdate- void $ tryNonAsync $ ensureInitialized+ catchNonAsync ensureInitialized (warning . show) Annex.getState Annex.repo s <- Annex.new r Annex.eval s $ check `finally` stopCoProcesses@@ -391,7 +393,6 @@ | not $ Git.repoIsUrl repo = ifM duc ( guardUsable repo (return False) $ commitOnCleanup repo r $ onLocalFast repo r $ do- ensureInitialized whenM (Annex.Content.inAnnex key) $ do Annex.Content.lockContentForRemoval key $ \lock -> do Annex.Content.removeAnnex lock@@ -489,7 +490,6 @@ hardlink <- wantHardLink -- run copy from perspective of remote onLocalFast repo r $ do- ensureInitialized v <- Annex.Content.prepSendAnnex key case v of Nothing -> return (False, UnVerified)@@ -631,7 +631,6 @@ onLocalFast repo r $ ifM (Annex.Content.inAnnex key) ( return True , do- ensureInitialized copier <- mkCopier hardlink st params let verify = Annex.Content.RemoteVerify r let rsp = RetrievalAllKeysSecure@@ -645,7 +644,7 @@ -- This is too broad really, but recvkey normally -- verifies content anyway, so avoid complicating -- it with a local sendAnnex check and rollback.- unlocked <- isDirect <||> versionSupportsUnlockedPointers+ let unlocked = True oh <- mkOutputHandlerQuiet Ssh.rsyncHelper oh (Just p) =<< Ssh.rsyncParamsRemote unlocked r Upload key object file@@ -681,21 +680,25 @@ - The AnnexState is cached for speed and to avoid resource leaks. - However, coprocesses are stopped after each call to avoid git - processes hanging around on removable media.+ -+ - The remote will be automatically initialized/upgraded first,+ - when possible. -} onLocal :: Git.Repo -> Remote -> Annex a -> Annex a onLocal repo r a = do m <- Annex.getState Annex.remoteannexstate- go =<< maybe- (liftIO $ Annex.new repo)- return- (M.lookup (uuid r) m)+ case M.lookup (uuid r) m of+ Nothing -> do+ st <- liftIO $ Annex.new repo+ go (st, ensureInitialized >> a)+ Just st -> go (st, a) where cache st = Annex.changeState $ \s -> s { Annex.remoteannexstate = M.insert (uuid r) st (Annex.remoteannexstate s) }- go st = do+ go (st, a') = do curro <- Annex.getState Annex.output (ret, st') <- liftIO $ Annex.run (st { Annex.output = curro }) $- a `finally` stopCoProcesses+ a' `finally` stopCoProcesses cache st' return ret @@ -719,13 +722,14 @@ {- Copys a file. Uses copy-on-write if it is supported. Otherwise, - uses rsync, so that interrupted copies can be resumed. -} rsyncOrCopyFile :: State -> [CommandParam] -> FilePath -> FilePath -> MeterUpdate -> Annex Bool-rsyncOrCopyFile st rsyncparams src dest p = #ifdef mingw32_HOST_OS+rsyncOrCopyFile _st _rsyncparams src dest p = -- rsync is only available on Windows in some installation methods, -- and is not strictly needed here, so don't use it. docopywith copyFileExternal where #else+rsyncOrCopyFile st rsyncparams src dest p = -- If multiple threads reach this at the same time, they -- will both try CoW, which is acceptable. ifM (liftIO $ isEmptyMVar copycowtried)@@ -775,8 +779,6 @@ wantHardLink :: Annex Bool wantHardLink = (annexHardLink <$> Annex.getGitConfig)- -- Not direct mode files because they can be modified at any time.- <&&> (not <$> isDirect) -- Not unlocked files that are hard linked in the work tree, -- because they can be modified at any time. <&&> (not <$> annexThin <$> Annex.getGitConfig)@@ -800,14 +802,13 @@ rsyncOrCopyFile st rsyncparams src dest p <&&> check localwanthardlink <- wantHardLink let linker = \src dest -> createLink src dest >> return True- ifM (pure (remotewanthardlink || localwanthardlink) <&&> not <$> isDirect)- ( return $ \src dest p check ->+ if remotewanthardlink || localwanthardlink+ then return $ \src dest p check -> ifM (liftIO (catchBoolIO (linker src dest))) ( return (True, Verified) , copier src dest p check )- , return copier- )+ else return copier {- Normally the UUID of a local repository is checked at startup, - but annex-checkuuid config can prevent that. To avoid getting
Test.hs view
@@ -30,7 +30,6 @@ import qualified Utility.SafeCommand import qualified Annex-import qualified Annex.Version import qualified Git.Filename import qualified Git.Types import qualified Git.Ref@@ -151,9 +150,7 @@ testmodes = catMaybes [ canadjust ("v7 adjusted unlocked branch", (testMode opts (RepoVersion 7)) { adjustedUnlockedBranch = True }) , unlesscrippled ("v7 unlocked", (testMode opts (RepoVersion 7)) { unlockedFiles = True })- , unlesscrippled ("v5", testMode opts (RepoVersion 5)) , unlesscrippled ("v7 locked", testMode opts (RepoVersion 7))- , Just ("v5 direct", (testMode opts (RepoVersion 5)) { forceDirect = True }) ] unlesscrippled v | crippledfilesystem = Nothing@@ -231,12 +228,11 @@ , testCase "move (ssh remote)" test_move_ssh_remote , testCase "copy" test_copy , testCase "lock" test_lock- , testCase "lock (v7 --force)" test_lock_v7_force+ , testCase "lock --force" test_lock_force , testCase "edit (no pre-commit)" test_edit , testCase "edit (pre-commit)" test_edit_precommit , testCase "partial commit" test_partial_commit , testCase "fix" test_fix- , testCase "direct" test_direct , testCase "trust" test_trust , testCase "fsck (basics)" test_fsck_basic , testCase "fsck (bare)" test_fsck_bare@@ -302,19 +298,11 @@ git_annex "unlock" [sha1annexedfile] @? "unlock failed" annexed_present sha1annexedfile checkbackend sha1annexedfile backendSHA1- ifM (annexeval Config.isDirect)- ( do- writecontent ingitfile $ content ingitfile- not <$> boolSystem "git" [Param "add", File ingitfile] @? "git add failed to fail in direct mode"- nukeFile ingitfile- git_annex "sync" [] @? "sync failed"- , do- writecontent ingitfile $ content ingitfile- boolSystem "git" [Param "add", File ingitfile] @? "git add failed"- boolSystem "git" [Param "commit", Param "-q", Param "-m", Param "commit"] @? "git commit failed"- git_annex "add" [ingitfile] @? "add ingitfile should be no-op"- unannexed ingitfile- )+ writecontent ingitfile $ content ingitfile+ boolSystem "git" [Param "add", File ingitfile] @? "git add failed"+ boolSystem "git" [Param "commit", Param "-q", Param "-m", Param "commit"] @? "git commit failed"+ git_annex "add" [ingitfile] @? "add ingitfile should be no-op"+ unannexed ingitfile test_add_dup :: Assertion test_add_dup = intmpclonerepo $ do@@ -394,7 +382,7 @@ return (importdir </> subdir, importdir </> importf, importf) test_reinject :: Assertion-test_reinject = intmpclonerepoInDirect $ do+test_reinject = intmpclonerepo $ do git_annex "drop" ["--force", sha1annexedfile] @? "drop failed" annexed_notpresent sha1annexedfile writecontent tmp $ content sha1annexedfile@@ -423,9 +411,8 @@ unannexed annexedfile git_annex "unannex" [annexedfile] @? "unannex failed on non-annexed file" unannexed annexedfile- unlessM (annexeval Config.isDirect) $ do- git_annex "unannex" [ingitfile] @? "unannex ingitfile should be no-op"- unannexed ingitfile+ git_annex "unannex" [ingitfile] @? "unannex ingitfile should be no-op"+ unannexed ingitfile test_drop_noremote :: Assertion test_drop_noremote = intmpclonerepo $ do@@ -437,9 +424,8 @@ git_annex "drop" ["--force", annexedfile] @? "drop --force failed" annexed_notpresent annexedfile git_annex "drop" [annexedfile] @? "drop of dropped file failed"- unlessM (annexeval Config.isDirect) $ do- git_annex "drop" [ingitfile] @? "drop ingitfile should be no-op"- unannexed ingitfile+ git_annex "drop" [ingitfile] @? "drop ingitfile should be no-op"+ unannexed ingitfile test_drop_withremote :: Assertion test_drop_withremote = intmpclonerepo $ do@@ -485,12 +471,11 @@ git_annex "get" [annexedfile] @? "get of file already here failed" inmainrepo $ annexed_present annexedfile annexed_present annexedfile- unlessM (annexeval Config.isDirect) $ do- inmainrepo $ unannexed ingitfile- unannexed ingitfile- git_annex "get" [ingitfile] @? "get ingitfile should be no-op"- inmainrepo $ unannexed ingitfile- unannexed ingitfile+ inmainrepo $ unannexed ingitfile+ unannexed ingitfile+ git_annex "get" [ingitfile] @? "get ingitfile should be no-op"+ inmainrepo $ unannexed ingitfile+ unannexed ingitfile test_move :: Assertion test_move = test_move' intmpclonerepo@@ -519,15 +504,14 @@ git_annex "move" ["--to", "origin", annexedfile] @? "move --to of file already there failed" inmainrepo $ annexed_present annexedfile annexed_notpresent annexedfile- unlessM (annexeval Config.isDirect) $ do- unannexed ingitfile- inmainrepo $ unannexed ingitfile- git_annex "move" ["--to", "origin", ingitfile] @? "move of ingitfile should be no-op"- unannexed ingitfile- inmainrepo $ unannexed ingitfile- git_annex "move" ["--from", "origin", ingitfile] @? "move of ingitfile should be no-op"- unannexed ingitfile- inmainrepo $ unannexed ingitfile+ unannexed ingitfile+ inmainrepo $ unannexed ingitfile+ git_annex "move" ["--to", "origin", ingitfile] @? "move of ingitfile should be no-op"+ unannexed ingitfile+ inmainrepo $ unannexed ingitfile+ git_annex "move" ["--from", "origin", ingitfile] @? "move of ingitfile should be no-op"+ unannexed ingitfile+ inmainrepo $ unannexed ingitfile test_copy :: Assertion test_copy = intmpclonerepo $ do@@ -545,15 +529,14 @@ git_annex "move" ["--to", "origin", annexedfile] @? "move --to of file already there failed" annexed_notpresent annexedfile inmainrepo $ annexed_present annexedfile- unlessM (annexeval Config.isDirect) $ do- unannexed ingitfile- inmainrepo $ unannexed ingitfile- git_annex "copy" ["--to", "origin", ingitfile] @? "copy of ingitfile should be no-op"- unannexed ingitfile- inmainrepo $ unannexed ingitfile- git_annex "copy" ["--from", "origin", ingitfile] @? "copy of ingitfile should be no-op"- checkregularfile ingitfile- checkcontent ingitfile+ unannexed ingitfile+ inmainrepo $ unannexed ingitfile+ git_annex "copy" ["--to", "origin", ingitfile] @? "copy of ingitfile should be no-op"+ unannexed ingitfile+ inmainrepo $ unannexed ingitfile+ git_annex "copy" ["--from", "origin", ingitfile] @? "copy of ingitfile should be no-op"+ checkregularfile ingitfile+ checkcontent ingitfile test_preferred_content :: Assertion test_preferred_content = intmpclonerepo $ do@@ -597,23 +580,14 @@ annexed_notpresent annexedfile test_lock :: Assertion-test_lock = intmpclonerepoInDirect $ do- annexed_notpresent annexedfile- unlessM (annexeval Annex.Version.versionSupportsUnlockedPointers) $- ifM (hasUnlockedFiles <$> getTestMode)- ( git_annex_shouldfail "lock" [annexedfile] @? "lock failed to fail with not present file"- , git_annex_shouldfail "unlock" [annexedfile] @? "unlock failed to fail with not present file"- )+test_lock = intmpclonerepo $ do annexed_notpresent annexedfile -- regression test: unlock of newly added, not committed file- -- should fail in v5 mode. In v7 mode, this is allowed.+ -- should not fail. writecontent "newfile" "foo" git_annex "add" ["newfile"] @? "add new file failed"- ifM (annexeval Annex.Version.versionSupportsUnlockedPointers)- ( git_annex "unlock" ["newfile"] @? "unlock failed on newly added, never committed file in v7 repository"- , git_annex_shouldfail "unlock" ["newfile"] @? "unlock failed to fail on newly added, never committed file in v5 repository"- )+ git_annex "unlock" ["newfile"] @? "unlock failed on newly added, never committed file" git_annex "get" [annexedfile] @? "get of file failed" annexed_present annexedfile@@ -625,21 +599,15 @@ writecontent annexedfile $ content annexedfile ++ "foo" git_annex_shouldfail "lock" [annexedfile] @? "lock failed to fail without --force" git_annex "lock" ["--force", annexedfile] @? "lock --force failed"- -- In v7 mode, the original content of the file is not always+ -- The original content of an unlocked file is not always -- preserved after modification, so re-get it. git_annex "get" [annexedfile] @? "get of file failed after lock --force" annexed_present_locked annexedfile git_annex "unlock" [annexedfile] @? "unlock failed" unannexed annexedfile changecontent annexedfile- ifM (annexeval Annex.Version.versionSupportsUnlockedPointers)- ( do- boolSystem "git" [Param "add", Param annexedfile] @? "add of modified file failed"- runchecks [checkregularfile, checkwritable] annexedfile- , do- git_annex "add" [annexedfile] @? "add of modified file failed"- runchecks [checklink, checkunwritable] annexedfile- )+ boolSystem "git" [Param "add", Param annexedfile] @? "add of modified file failed"+ runchecks [checkregularfile, checkwritable] annexedfile c <- readFile annexedfile assertEqual "content of modified file" c (changedcontent annexedfile) r' <- git_annex "drop" [annexedfile]@@ -648,21 +616,20 @@ -- Regression test: lock --force when work tree file -- was modified lost the (unmodified) annex object. -- (Only occurred when the keys database was out of sync.)-test_lock_v7_force :: Assertion-test_lock_v7_force = intmpclonerepoInDirect $ do+test_lock_force :: Assertion+test_lock_force = intmpclonerepo $ do git_annex "upgrade" [] @? "upgrade failed"- whenM (annexeval Annex.Version.versionSupportsUnlockedPointers) $ do- git_annex "get" [annexedfile] @? "get of file failed"- git_annex "unlock" [annexedfile] @? "unlock failed in v7 mode"- annexeval $ do- Just k <- Annex.WorkTree.lookupFile annexedfile- Database.Keys.removeInodeCaches k- Database.Keys.closeDb- liftIO . nukeFile =<< Annex.fromRepo Annex.Locations.gitAnnexKeysDbIndexCache- writecontent annexedfile "test_lock_v7_force content"- git_annex_shouldfail "lock" [annexedfile] @? "lock of modified file failed to fail in v7 mode"- git_annex "lock" ["--force", annexedfile] @? "lock --force of modified file failed in v7 mode"- annexed_present_locked annexedfile+ git_annex "get" [annexedfile] @? "get of file failed"+ git_annex "unlock" [annexedfile] @? "unlock failed"+ annexeval $ do+ Just k <- Annex.WorkTree.lookupFile annexedfile+ Database.Keys.removeInodeCaches k+ Database.Keys.closeDb+ liftIO . nukeFile =<< Annex.fromRepo Annex.Locations.gitAnnexKeysDbIndexCache+ writecontent annexedfile "test_lock_force content"+ git_annex_shouldfail "lock" [annexedfile] @? "lock of modified file failed to fail"+ git_annex "lock" ["--force", annexedfile] @? "lock --force of modified file failed"+ annexed_present_locked annexedfile test_edit :: Assertion test_edit = test_edit' False@@ -671,7 +638,7 @@ test_edit_precommit = test_edit' True test_edit' :: Bool -> Assertion-test_edit' precommit = intmpclonerepoInDirect $ do+test_edit' precommit = intmpclonerepo $ do git_annex "get" [annexedfile] @? "get of file failed" annexed_present annexedfile git_annex "edit" [annexedfile] @? "edit failed"@@ -684,29 +651,22 @@ @? "pre-commit failed" else boolSystem "git" [Param "commit", Param "-q", Param "-m", Param "contentchanged"] @? "git commit of edited file failed"- ifM (annexeval Annex.Version.versionSupportsUnlockedPointers)- ( runchecks [checkregularfile, checkwritable] annexedfile- , runchecks [checklink, checkunwritable] annexedfile- )+ runchecks [checkregularfile, checkwritable] annexedfile c <- readFile annexedfile assertEqual "content of modified file" c (changedcontent annexedfile) git_annex_shouldfail "drop" [annexedfile] @? "drop wrongly succeeded with no known copy of modified file" test_partial_commit :: Assertion-test_partial_commit = intmpclonerepoInDirect $ do+test_partial_commit = intmpclonerepo $ do git_annex "get" [annexedfile] @? "get of file failed" annexed_present annexedfile git_annex "unlock" [annexedfile] @? "unlock failed" changecontent annexedfile- ifM (annexeval Annex.Version.versionSupportsUnlockedPointers)- ( boolSystem "git" [Param "commit", Param "-q", Param "-m", Param "test", File annexedfile]- @? "partial commit of unlocked file should be allowed in v7 repository"- , not <$> boolSystem "git" [Param "commit", Param "-q", Param "-m", Param "test", File annexedfile]- @? "partial commit of unlocked file not blocked by pre-commit hook"- )+ boolSystem "git" [Param "commit", Param "-q", Param "-m", Param "test", File annexedfile]+ @? "partial commit of unlocked file should be allowed" test_fix :: Assertion-test_fix = intmpclonerepoInDirect $ unlessM (hasUnlockedFiles <$> getTestMode) $ do+test_fix = intmpclonerepo $ unlessM (hasUnlockedFiles <$> getTestMode) $ do annexed_notpresent annexedfile git_annex "fix" [annexedfile] @? "fix of not present failed" annexed_notpresent annexedfile@@ -725,18 +685,6 @@ subdir = "s" newfile = subdir ++ "/" ++ annexedfile -test_direct :: Assertion-test_direct = intmpclonerepoInDirect $ do- git_annex "get" [annexedfile] @? "get of file failed"- annexed_present annexedfile- ifM (annexeval Annex.Version.versionSupportsUnlockedPointers)- ( git_annex_shouldfail "direct" [] @? "switch to direct mode failed to fail in v7 repository"- , do- git_annex "direct" [] @? "switch to direct mode failed"- annexed_present annexedfile- git_annex "indirect" [] @? "switch to indirect mode failed"- )- test_trust :: Assertion test_trust = intmpclonerepo $ do git_annex "trust" [repo] @? "trust failed"@@ -777,7 +725,7 @@ git_annex "get" [f] @? "get of file failed" Utility.FileMode.allowWrite f writecontent f (changedcontent f)- ifM (annexeval Config.isDirect <||> hasUnlockedFiles <$> getTestMode)+ ifM (hasUnlockedFiles <$> getTestMode) ( git_annex "fsck" [] @? "fsck failed on unlocked file with changed file content" , git_annex_shouldfail "fsck" [] @? "fsck failed to fail with corrupted file content" )@@ -820,7 +768,7 @@ test_migrate_via_gitattributes = test_migrate' True test_migrate' :: Bool -> Assertion-test_migrate' usegitattributes = intmpclonerepoInDirect $ do+test_migrate' usegitattributes = intmpclonerepo $ do annexed_notpresent annexedfile annexed_notpresent sha1annexedfile git_annex "migrate" [annexedfile] @? "migrate of not present failed"@@ -858,8 +806,7 @@ checkbackend sha1annexedfile backendSHA256 test_unused :: Assertion--- This test is broken in direct mode.-test_unused = intmpclonerepoInDirect $ do+test_unused = intmpclonerepo $ do checkunused [] "in new clone" git_annex "get" [annexedfile] @? "get of file failed" git_annex "get" [sha1annexedfile] @? "get of file failed"@@ -991,10 +938,6 @@ test_sync :: Assertion test_sync = intmpclonerepo $ do git_annex "sync" [] @? "sync failed"- {- Regression test for bug fixed in - - 7b0970b340d7faeb745c666146c7f701ec71808f, where in direct mode- - sync committed the symlink standin file to the annex. -}- git_annex_expectoutput "find" ["--in", "."] [] {- Regression test for bug fixed in - 039e83ed5d1a11fd562cce55b8429c840d72443e, where a present - wanted file was dropped. -}@@ -1051,12 +994,8 @@ forM_ [r1, r2] $ \r -> indir r $ do {- Set up a conflict. -} let newcontent = content annexedfile ++ rname r- ifM (annexeval Config.isDirect)- ( writecontent annexedfile newcontent- , do- git_annex "unlock" [annexedfile] @? "unlock failed" - writecontent annexedfile newcontent- )+ git_annex "unlock" [annexedfile] @? "unlock failed" + writecontent annexedfile newcontent {- Sync twice in r1 so it gets the conflict resolution - update from r2 -} forM_ [r1, r2, r1] $ \r -> indir r $@@ -1065,9 +1004,8 @@ - files. This includes both sides of the conflict, - although the filenames are not easily predictable. -- - The bug caused, in direct mode, one repo to- - be missing the content of the file that had- - been put in it. -}+ - The bug caused one repo to be missing the content+ - of the file that had been put in it. -} forM_ [r1, r2] $ \r -> indir r $ do git_annex "get" [] @? "unable to get all files after merge conflict resolution in " ++ rname r @@ -1120,8 +1058,6 @@ writecontent conflictor "conflictor2" add_annex conflictor @? "add conflicter failed" git_annex "sync" [] @? "sync failed in r2"- -- need v7 to use adjust- git_annex "upgrade" [] @? "upgrade failed" -- We might be in an adjusted branch -- already, when eg on a crippled -- filesystem. So, --force it.@@ -1207,9 +1143,8 @@ git_annex "sync" [] @? "sync failed in r2" git_annex "get" [conflictor] @? "get conflictor failed"- unlessM (annexeval Config.isDirect) $ do- git_annex "unlock" [conflictor]- @? "unlock conflictor failed"+ git_annex "unlock" [conflictor]+ @? "unlock conflictor failed" writecontent conflictor "newconflictor" indir r1 $ nukeFile conflictor@@ -1230,44 +1165,35 @@ {- Check merge confalict resolution when a file is annexed in one repo, - and checked directly into git in the other repo.- -- - This test requires indirect mode to set it up, but tests both direct and- - indirect mode. -} test_nonannexed_file_conflict_resolution :: Assertion test_nonannexed_file_conflict_resolution = do- check True False- check False False- check True True- check False True+ check True+ check False where- check inr1 switchdirect = withtmpclonerepo $ \r1 ->- withtmpclonerepo $ \r2 ->- whenM (isInDirect r1 <&&> isInDirect r2) $ do- indir r1 $ do- disconnectOrigin- writecontent conflictor "conflictor"- add_annex conflictor @? "add conflicter failed"- git_annex "sync" [] @? "sync failed in r1"- indir r2 $ do- disconnectOrigin- writecontent conflictor nonannexed_content- boolSystem "git"- [ Param "config"- , Param "annex.largefiles"- , Param ("exclude=" ++ ingitfile ++ " and exclude=" ++ conflictor)- ] @? "git config annex.largefiles failed"- boolSystem "git" [Param "add", File conflictor] @? "git add conflictor failed"- git_annex "sync" [] @? "sync failed in r2"- pair r1 r2- let l = if inr1 then [r1, r2] else [r2, r1]- forM_ l $ \r -> indir r $ do- when switchdirect $- whenM (annexeval Annex.Version.versionSupportsDirectMode) $- git_annex "direct" [] @? "failed switching to direct mode"- git_annex "sync" [] @? "sync failed"- checkmerge ("r1" ++ show switchdirect) r1- checkmerge ("r2" ++ show switchdirect) r2+ check inr1 = withtmpclonerepo $ \r1 ->+ withtmpclonerepo $ \r2 -> do+ indir r1 $ do+ disconnectOrigin+ writecontent conflictor "conflictor"+ add_annex conflictor @? "add conflicter failed"+ git_annex "sync" [] @? "sync failed in r1"+ indir r2 $ do+ disconnectOrigin+ writecontent conflictor nonannexed_content+ boolSystem "git"+ [ Param "config"+ , Param "annex.largefiles"+ , Param ("exclude=" ++ ingitfile ++ " and exclude=" ++ conflictor)+ ] @? "git config annex.largefiles failed"+ boolSystem "git" [Param "add", File conflictor] @? "git add conflictor failed"+ git_annex "sync" [] @? "sync failed in r2"+ pair r1 r2+ let l = if inr1 then [r1, r2] else [r2, r1]+ forM_ l $ \r -> indir r $+ git_annex "sync" [] @? "sync failed"+ checkmerge "r1" r1+ checkmerge "r2" r2 conflictor = "conflictor" nonannexed_content = "nonannexed" variantprefix = conflictor ++ ".variant"@@ -1284,7 +1210,7 @@ @? (what ++ " wrong content for nonannexed file: " ++ show s) -{- Check merge confalict resolution when a file is annexed in one repo,+{- Check merge conflict resolution when a file is annexed in one repo, - and is a non-git-annex symlink in the other repo. - - Test can only run when coreSymlinks is supported, because git needs to@@ -1292,15 +1218,12 @@ -} test_nonannexed_symlink_conflict_resolution :: Assertion test_nonannexed_symlink_conflict_resolution = do- check True False- check False False- check True True- check False True+ check True+ check False where- check inr1 switchdirect = withtmpclonerepo $ \r1 ->+ check inr1 = withtmpclonerepo $ \r1 -> withtmpclonerepo $ \r2 ->- whenM (checkRepo (Types.coreSymlinks <$> Annex.getGitConfig) r1- <&&> isInDirect r1 <&&> isInDirect r2) $ do+ whenM (checkRepo (Types.coreSymlinks <$> Annex.getGitConfig) r1) $ do indir r1 $ do disconnectOrigin writecontent conflictor "conflictor"@@ -1313,13 +1236,10 @@ git_annex "sync" [] @? "sync failed in r2" pair r1 r2 let l = if inr1 then [r1, r2] else [r2, r1]- forM_ l $ \r -> indir r $ do- when switchdirect $- whenM (annexeval Annex.Version.versionSupportsDirectMode) $ do- git_annex "direct" [] @? "failed switching to direct mode"+ forM_ l $ \r -> indir r $ git_annex "sync" [] @? "sync failed"- checkmerge ("r1" ++ show switchdirect) r1- checkmerge ("r2" ++ show switchdirect) r2+ checkmerge "r1" r1+ checkmerge "r2" r2 conflictor = "conflictor" symlinktarget = "dummy-target" variantprefix = conflictor ++ ".variant"@@ -1361,24 +1281,11 @@ disconnectOrigin writecontent conflictor localcontent pair r1 r2- indir r2 $ ifM (annexeval Config.isDirect)- ( do- git_annex "sync" [] @? "sync failed"- let local = conflictor ++ localprefix- doesFileExist local @? (local ++ " missing after merge")- s <- readFile local- s == localcontent @? (local ++ " has wrong content: " ++ s)- git_annex "get" [conflictor] @? "get failed"- doesFileExist remoteconflictor @? (remoteconflictor ++ " missing after merge")- s' <- readFile remoteconflictor- s' == annexedcontent @? (remoteconflictor ++ " has wrong content: " ++ s)- -- this case is intentionally not handled- -- in indirect mode, since the user- -- can recover on their own easily- , git_annex_shouldfail "sync" [] @? "sync failed to fail"- )+ -- this case is intentionally not handled+ -- since the user can recover on their own easily+ indir r2 $ git_annex_shouldfail "sync" []+ @? "sync failed to fail" conflictor = "conflictor"- localprefix = ".variant-local" localcontent = "local" annexedcontent = "annexed" @@ -1414,19 +1321,19 @@ all (\i -> Git.Types.toTreeItemType (Git.LsTree.mode i) == Just Git.Types.TreeSymlink) l @? (what ++ " " ++ f ++ " lost symlink bit after merge: " ++ show l) -{- A v7 unlocked file that conflicts with a locked file should be resolved+{- An unlocked file that conflicts with a locked file should be resolved - in favor of the unlocked file, with no variant files, as long as they - both point to the same key. -} test_mixed_lock_conflict_resolution :: Assertion test_mixed_lock_conflict_resolution = withtmpclonerepo $ \r1 -> withtmpclonerepo $ \r2 -> do- indir r1 $ whenM shouldtest $ do+ indir r1 $ do disconnectOrigin writecontent conflictor "conflictor" git_annex "add" [conflictor] @? "add conflicter failed" git_annex "sync" [] @? "sync failed in r1"- indir r2 $ whenM shouldtest $ do+ indir r2 $ do disconnectOrigin writecontent conflictor "conflictor" git_annex "add" [conflictor] @? "add conflicter failed"@@ -1438,10 +1345,9 @@ checkmerge "r1" r1 checkmerge "r2" r2 where- shouldtest = annexeval Annex.Version.versionSupportsUnlockedPointers conflictor = "conflictor" variantprefix = conflictor ++ ".variant"- checkmerge what d = indir d $ whenM shouldtest $ do+ checkmerge what d = indir d $ do l <- getDirectoryContents "." let v = filter (variantprefix `isPrefixOf`) l length v == 0@@ -1527,7 +1433,7 @@ doesDirectoryExist ".git" @? ".git vanished in uninit" test_uninit_inbranch :: Assertion-test_uninit_inbranch = intmpclonerepoInDirect $ do+test_uninit_inbranch = intmpclonerepo $ do boolSystem "git" [Param "checkout", Param "git-annex"] @? "git checkout git-annex" git_annex_shouldfail "uninit" [] @? "uninit failed to fail when git-annex branch was checked out" @@ -1744,7 +1650,7 @@ doesFileExist dest @? (dest ++ " missing after addurl --file") test_export_import :: Assertion-test_export_import = intmpclonerepoInDirect $ do+test_export_import = intmpclonerepo $ do createDirectory "dir" git_annex "initremote" (words "foo type=directory encryption=none directory=dir exporttree=yes importtree=yes") @? "initremote failed" git_annex "get" [] @? "get of files failed"@@ -1798,7 +1704,7 @@ commitchanges = git_annex "sync" ["--no-pull", "--no-push"] @? "sync failed" test_export_import_subdir :: Assertion-test_export_import_subdir = intmpclonerepoInDirect $ do+test_export_import_subdir = intmpclonerepo $ do createDirectory "dir" git_annex "initremote" (words "foo type=directory encryption=none directory=dir exporttree=yes importtree=yes") @? "initremote failed" git_annex "get" [] @? "get of files failed"
Test/Framework.hs view
@@ -31,7 +31,6 @@ import qualified Config import qualified Annex.WorkTree import qualified Annex.Link-import qualified Annex.Init import qualified Annex.Path import qualified Annex.Action import qualified Annex.AdjustedBranch@@ -98,26 +97,12 @@ intmpclonerepo :: Assertion -> Assertion intmpclonerepo a = withtmpclonerepo $ \r -> indir r a -intmpclonerepoInDirect :: Assertion -> Assertion-intmpclonerepoInDirect a = intmpclonerepo $- ifM isdirect- ( putStrLn "not supported in direct mode; skipping"- , a- )- where- isdirect = annexeval $ do- Annex.Init.initialize Nothing Nothing- Config.isDirect- checkRepo :: Types.Annex a -> FilePath -> IO a checkRepo getval d = do s <- Annex.new =<< Git.Construct.fromPath d Annex.eval s $ getval `finally` Annex.Action.stopCoProcesses -isInDirect :: FilePath -> IO Bool-isInDirect = checkRepo (not <$> Config.isDirect)- intmpbareclonerepo :: Assertion -> Assertion intmpbareclonerepo a = withtmpclonerepo' (newCloneRepoConfig { bareClone = True } ) $ \r -> indir r a@@ -165,7 +150,7 @@ Left e -> throwM e adjustedbranchsupported :: FilePath -> IO Bool-adjustedbranchsupported repo = indir repo $ annexeval Annex.AdjustedBranch.isSupported+adjustedbranchsupported repo = indir repo $ Annex.AdjustedBranch.isGitVersionSupported setuprepo :: FilePath -> IO FilePath setuprepo dir = do@@ -259,17 +244,13 @@ removeDirectoryRecursive tmpdir checklink :: FilePath -> Assertion-checklink f =- -- in direct mode, it may be a symlink, or not, depending- -- on whether the content is present.- unlessM (annexeval Config.isDirect) $- ifM (annexeval Config.crippledFileSystem)- ( (isJust <$> annexeval (Annex.Link.getAnnexLinkTarget f))- @? f ++ " is not a (crippled) symlink"- , do- s <- getSymbolicLinkStatus f- isSymbolicLink s @? f ++ " is not a symlink"- )+checklink f = ifM (annexeval Config.crippledFileSystem)+ ( (isJust <$> annexeval (Annex.Link.getAnnexLinkTarget f))+ @? f ++ " is not a (crippled) symlink"+ , do+ s <- getSymbolicLinkStatus f+ isSymbolicLink s @? f ++ " is not a symlink"+ ) checkregularfile :: FilePath -> Assertion checkregularfile f = do@@ -293,7 +274,7 @@ assertEqual ("checkcontent " ++ f) (content f) c checkunwritable :: FilePath -> Assertion-checkunwritable f = unlessM (annexeval Config.isDirect) $ do+checkunwritable f = do -- Look at permissions bits rather than trying to write or -- using fileAccess because if run as root, any file can be -- modified despite permissions.@@ -408,8 +389,7 @@ ) data TestMode = TestMode- { forceDirect :: Bool- , unlockedFiles :: Bool+ { unlockedFiles :: Bool , adjustedUnlockedBranch :: Bool , annexVersion :: Types.RepoVersion.RepoVersion , keepFailures :: Bool@@ -417,8 +397,7 @@ testMode :: TestOptions -> Types.RepoVersion.RepoVersion -> TestMode testMode opts v = TestMode- { forceDirect = False- , unlockedFiles = False+ { unlockedFiles = False , adjustedUnlockedBranch = False , annexVersion = v , keepFailures = keepFailuresOption opts@@ -477,8 +456,6 @@ setupTestMode :: IO () setupTestMode = do testmode <- getTestMode- when (forceDirect testmode) $- git_annex "direct" ["-q"] @? "git annex direct failed" when (adjustedUnlockedBranch testmode) $ do boolSystem "git" [Param "commit", Param "--allow-empty", Param "-m", Param "empty"] @? "git commit failed" git_annex "adjust" ["--unlock"] @? "git annex adjust failed"
Types/GitConfig.hs view
@@ -103,6 +103,7 @@ , annexMaxExtensionLength :: Maybe Int , annexJobs :: Concurrency , annexCacheCreds :: Bool+ , annexAutoUpgradeRepository :: Bool , coreSymlinks :: Bool , coreSharedRepository :: SharedRepository , receiveDenyCurrentBranch :: DenyCurrentBranch@@ -182,6 +183,7 @@ , annexJobs = fromMaybe NonConcurrent $ parseConcurrency =<< getmaybe (annex "jobs") , annexCacheCreds = getbool (annex "cachecreds") True+ , annexAutoUpgradeRepository = getbool (annex "autoupgraderepository") True , coreSymlinks = getbool "core.symlinks" True , coreSharedRepository = getSharedRepository r , receiveDenyCurrentBranch = getDenyCurrentBranch r
Upgrade.hs view
@@ -1,6 +1,6 @@ {- git-annex upgrade support -- - Copyright 2010, 2013 Joey Hess <id@joeyh.name>+ - Copyright 2010-2019 Joey Hess <id@joeyh.name> - - Licensed under the GNU AGPL version 3 or higher. -}@@ -10,6 +10,8 @@ module Upgrade where import Annex.Common+import qualified Annex+import qualified Git import Annex.Version import Types.RepoVersion #ifndef mingw32_HOST_OS@@ -36,14 +38,23 @@ err "Upgrade this repository: git-annex upgrade" | otherwise -> err "Upgrade git-annex."- Just newv -> ifM (upgrade True newv)- ( ok- , err "Automatic upgrade failed!"+ Just newv -> ifM (annexAutoUpgradeRepository <$> Annex.getGitConfig)+ ( tryNonAsync (upgrade True newv) >>= \case+ Right True -> ok+ Right False -> err "Automatic upgrade failed!"+ Left ex -> err $ "Automatic upgrade exception! " ++ show ex+ , err "Automatic upgrade is disabled by annex.autoupgraderepository configuration. To upgrade this repository: git-annex upgrade" ) where- err msg = return $ Just $ "Repository version " ++- show (fromRepoVersion v) ++- " is not supported. " ++ msg+ err msg = do+ g <- Annex.gitRepo+ p <- liftIO $ absPath $ Git.repoPath g+ return $ Just $ unwords+ [ "Repository", p+ , "is at unsupported version"+ , show (fromRepoVersion v) ++ "."+ , msg+ ] ok = return Nothing upgrade :: Bool -> RepoVersion -> Annex Bool@@ -74,3 +85,4 @@ up (RepoVersion 5) = Upgrade.V5.upgrade automatic up (RepoVersion 6) = Upgrade.V6.upgrade automatic up _ = return True+
Upgrade/V4.hs view
@@ -8,16 +8,8 @@ module Upgrade.V4 where import Annex.Common-import Config-import Annex.Direct -{- Direct mode only upgrade. v4 to v5 indirect update is a no-op -}+{- Was only used for direct mode upgrade. v4 to v5 indirect update is a no-op,+ - and direct mode is no longer supported, so nothing needs to be done. -} upgrade :: Bool -> Annex Bool-upgrade automatic = ifM isDirect- ( do- unless automatic $- showAction "v4 to v5"- setDirect True- return True- , return True- )+upgrade _automatic = return True
Upgrade/V5.hs view
@@ -1,6 +1,6 @@ {- git-annex v5 -> v6 upgrade support -- - Copyright 2015-2016 Joey Hess <id@joeyh.name>+ - Copyright 2015-2019 Joey Hess <id@joeyh.name> - - Licensed under the GNU AGPL version 3 or higher. -}@@ -13,78 +13,99 @@ import Config.Smudge import Annex.InodeSentinal import Annex.Link-import Annex.Direct-import Annex.Content import Annex.CatFile import Annex.WorkTree+import Annex.UUID+import Logs.Location+import qualified Upgrade.V5.Direct as Direct+import qualified Annex.Content as Content import qualified Database.Keys-import qualified Annex.Content.Direct as Direct import qualified Git import qualified Git.LsFiles import qualified Git.Branch+import qualified Git.Version import Git.FilePath import Git.FileMode import Git.Config import Git.Ref import Utility.InodeCache+import Utility.DottedVersion import Annex.AdjustedBranch import qualified Data.ByteString as S upgrade :: Bool -> Annex Bool-upgrade automatic = do+upgrade automatic = flip catchNonAsync (const $ return False) $ do unless automatic $ showAction "v5 to v6"- whenM isDirect $ do- {- Direct mode makes the same tradeoff of using less disk- - space, with less preservation of old versions of files- - as does annex.thin. -}- setConfig (annexConfig "thin") (boolConfig True)- Annex.changeGitConfig $ \c -> c { annexThin = True }- {- Since upgrade from direct mode changes how files- - are represented in git, by checking out an adjusted- - branch, commit any changes in the work tree first. -}- whenM stageDirect $ do- unless automatic $- showAction "committing first"- upgradeDirectCommit automatic- "commit before upgrade to annex.version 6"- setDirect False- cur <- fromMaybe (error "Somehow no branch is checked out")- <$> inRepo Git.Branch.current- upgradeDirectWorkTree- removeDirectCruft- {- Create adjusted branch where all files are unlocked.- - This should have the same content for each file as- - have been staged in upgradeDirectWorkTree. -}- AdjBranch b <- adjustBranch (LinkAdjustment UnlockAdjustment) cur- {- Since the work tree was already set up by- - upgradeDirectWorkTree, and contains unlocked file- - contents too, don't use git checkout to check out the- - adjust branch. Instead, update HEAD manually. -}- inRepo $ setHeadRef b- scanUnlockedFiles+ ifM isDirect+ ( do+ checkGitVersionForDirectUpgrade+ convertDirect+ -- Worktree files are already populated, so don't+ -- have this try to populate them again.+ scanUnlockedFiles False+ , do+ checkGitVersionForIndirectUpgrade+ scanUnlockedFiles True+ ) configureSmudgeFilter -- Inode sentinal file was only used in direct mode and when -- locking down files as they were added. In v6, it's used more -- extensively, so make sure it exists, since old repos that didn't -- use direct mode may not have created it.- unlessM (isDirect) $+ unlessM isDirect $ createInodeSentinalFile True return True -upgradeDirectCommit :: Bool -> String -> Annex ()-upgradeDirectCommit automatic msg = - void $ inRepo $ Git.Branch.commitCommand commitmode- [ Param "-m"- , Param msg- ]- where- commitmode = if automatic then Git.Branch.AutomaticCommit else Git.Branch.ManualCommit+-- git before 2.22 would OOM running git status on a large file.+--+-- Older versions of git that are patched (with+-- commit 02156ab031e430bc45ce6984dfc712de9962dec8)+-- can include "oomfix" in their version to indicate it.+gitWillOOM :: Annex Bool+gitWillOOM = liftIO $ do+ v <- Git.Version.installed+ return $ v < Git.Version.normalize "2.22" &&+ not ("oomfix" `isInfixOf` fromDottedVersion v) +-- configureSmudgeFilter has to run git status, and direct mode files+-- are unlocked, so avoid the upgrade failing half way through.+checkGitVersionForDirectUpgrade :: Annex ()+checkGitVersionForDirectUpgrade = whenM gitWillOOM $+ giveup "You must upgrade git to version 2.22 or newer in order to use this version of git-annex in this repository."++checkGitVersionForIndirectUpgrade :: Annex ()+checkGitVersionForIndirectUpgrade = whenM gitWillOOM $+ warning "Git is older than version 2.22 and so it has a memory leak that affects using unlocked files. Recommend you upgrade git before unlocking any files in your repository."++convertDirect :: Annex ()+convertDirect = do+ {- Direct mode makes the same tradeoff of using less disk+ - space, with less preservation of old versions of files+ - as does annex.thin. -}+ setConfig (annexConfig "thin") (boolConfig True)+ Annex.changeGitConfig $ \c -> c { annexThin = True }+ Direct.setIndirect+ cur <- fromMaybe (error "Somehow no branch is checked out")+ <$> inRepo Git.Branch.current+ upgradeDirectWorkTree+ removeDirectCruft+ {- Create adjusted branch where all files are unlocked.+ - This should have the same content for each file as+ - have been staged in upgradeDirectWorkTree. -}+ AdjBranch b <- adjustBranch (LinkAdjustment UnlockAdjustment) cur+ {- Since the work tree was already set up by+ - upgradeDirectWorkTree, and contains unlocked file+ - contents too, don't use git checkout to check out the+ - adjust branch. Instead, update HEAD manually. -}+ inRepo $ setHeadRef b+ {- Walk work tree from top and convert all annex symlinks to pointer files,- - staging them in the index, and updating the work tree files with- - either the content of the object, or the pointer file content. -}+ - staging them in the index, and populating the annex objects with+ - hard links (or copies) of the work tree files (when not modified or+ - deleted).+ -} upgradeDirectWorkTree :: Annex () upgradeDirectWorkTree = do top <- fromRepo Git.repoPath@@ -99,31 +120,41 @@ case mk of Nothing -> noop Just k -> do+ stagePointerFile f Nothing =<< hashPointerFile k ifM (isJust <$> getAnnexLinkTarget f) ( writepointer f k , fromdirect f k )- stagePointerFile f Nothing =<< hashPointerFile k Database.Keys.addAssociatedFile k =<< inRepo (toTopFilePath f)- return () go _ = noop - fromdirect f k = do- -- If linkToAnnex fails for some reason, the work tree file- -- still has the content; the annex object file is just- -- not populated with it. Since the work tree file- -- is recorded as an associated file, things will still- -- work that way, it's just not ideal.- ic <- withTSDelta (liftIO . genInodeCache f)- void $ linkToAnnex k f ic+ fromdirect f k = ifM (Direct.goodContent k f)+ ( do+ -- If linkToAnnex fails for some reason, the work tree+ -- file still has the content; the annex object file+ -- is just not populated with it. Since the work tree+ -- file is recorded as an associated file, things will+ -- still work that way, it's just not ideal.+ ic <- withTSDelta (liftIO . genInodeCache f)+ void $ Content.linkToAnnex k f ic+ , unlessM (Content.inAnnex k) $ do+ -- Worktree file was deleted or modified;+ -- if there are no other copies of the content+ -- then it's been lost.+ locs <- Direct.associatedFiles k+ unlessM (anyM (Direct.goodContent k) locs) $ do+ u <- getUUID+ logChange k u InfoMissing+ )+ writepointer f k = liftIO $ do nukeFile f S.writeFile f (formatPointer k) {- Remove all direct mode bookkeeping files. -} removeDirectCruft :: Annex ()-removeDirectCruft = mapM_ go =<< getKeysPresent InAnywhere+removeDirectCruft = mapM_ go =<< Content.listKeys Content.InAnywhere where go k = do Direct.removeInodeCache k
+ Upgrade/V5/Direct.hs view
@@ -0,0 +1,126 @@+{- git-annex direct mode+ -+ - This only contains some remnants needed to convert away from direct mode.+ -+ - Copyright 2012-2014 Joey Hess <id@joeyh.name>+ -+ - Licensed under the GNU AGPL version 3 or higher.+ -}++module Upgrade.V5.Direct (+ switchHEADBack,+ setIndirect,+ goodContent,+ associatedFiles,+ removeAssociatedFiles,+ removeInodeCache,+) where++import Annex.Common+import qualified Annex+import qualified Git+import qualified Git.Config+import qualified Git.Ref+import qualified Git.Branch+import Git.Types+import Config+import Annex.Perms+import Utility.InodeCache+import Annex.InodeSentinal++setIndirect :: Annex ()+setIndirect = do+ setbare+ switchHEADBack+ setConfig (annexConfig "direct") val+ Annex.changeGitConfig $ \c -> c { annexDirect = False }+ where+ val = Git.Config.boolConfig False+ coreworktree = ConfigKey "core.worktree"+ indirectworktree = ConfigKey "core.indirect-worktree"+ setbare = do+ -- core.worktree is not compatable with+ -- core.bare; git does not allow both to be set, so+ -- unset it when enabling direct mode, caching in+ -- core.indirect-worktree+ moveconfig indirectworktree coreworktree+ setConfig (ConfigKey Git.Config.coreBare) val+ moveconfig src dest = getConfigMaybe src >>= \case+ Nothing -> noop+ Just wt -> do+ unsetConfig src+ setConfig dest wt+ reloadConfig++{- Converts a directBranch back to the original branch.+ -+ - Any other ref is left unchanged.+ -}+fromDirectBranch :: Ref -> Ref+fromDirectBranch directhead = case splitc '/' $ fromRef directhead of+ ("refs":"heads":"annex":"direct":rest) -> + Ref $ "refs/heads/" ++ intercalate "/" rest+ _ -> directhead++switchHEADBack :: Annex ()+switchHEADBack = maybe noop switch =<< inRepo Git.Branch.currentUnsafe+ where+ switch currhead = do+ let orighead = fromDirectBranch currhead+ inRepo (Git.Ref.sha currhead) >>= \case+ Just headsha+ | orighead /= currhead -> do+ inRepo $ Git.Branch.update "leaving direct mode" orighead headsha+ inRepo $ Git.Branch.checkout orighead+ inRepo $ Git.Branch.delete currhead+ _ -> inRepo $ Git.Branch.checkout orighead++{- Absolute FilePaths of Files in the tree that are associated with a key. -}+associatedFiles :: Key -> Annex [FilePath]+associatedFiles key = do+ files <- associatedFilesRelative key+ top <- fromRepo Git.repoPath+ return $ map (top </>) files++{- List of files in the tree that are associated with a key, relative to+ - the top of the repo. -}+associatedFilesRelative :: Key -> Annex [FilePath] +associatedFilesRelative key = do+ mapping <- calcRepo $ gitAnnexMapping key+ liftIO $ catchDefaultIO [] $ withFile mapping ReadMode $ \h ->+ -- Read strictly to ensure the file is closed promptly+ lines <$> hGetContentsStrict h++{- Removes the list of associated files. -}+removeAssociatedFiles :: Key -> Annex ()+removeAssociatedFiles key = do+ mapping <- calcRepo $ gitAnnexMapping key+ modifyContent mapping $+ liftIO $ nukeFile mapping++{- 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+ - expensive checksum, this relies on a cache that contains the file's+ - expected mtime and inode.+ -}+goodContent :: Key -> FilePath -> Annex Bool+goodContent key file = sameInodeCache file =<< recordedInodeCache key++{- Gets the recorded inode cache for a key. + -+ - A key can be associated with multiple files, so may return more than+ - one. -}+recordedInodeCache :: Key -> Annex [InodeCache]+recordedInodeCache key = withInodeCacheFile key $ \f ->+ liftIO $ catchDefaultIO [] $+ mapMaybe readInodeCache . lines <$> readFileStrict f++{- Removes an inode cache. -}+removeInodeCache :: Key -> Annex ()+removeInodeCache key = withInodeCacheFile key $ \f ->+ modifyContent f $+ liftIO $ nukeFile f++withInodeCacheFile :: Key -> (FilePath -> Annex a) -> Annex a+withInodeCacheFile key a = a =<< calcRepo (gitAnnexInodeCache key)
Utility/CopyFile.hs view
@@ -35,7 +35,8 @@ allmeta = meta == CopyAllMetaData {- The cp command is used, because I hate reinventing the wheel,- - and because this allows easy access to features like cp --reflink. -}+ - and because this allows easy access to features like cp --reflink+ - and preserving metadata. -} copyFileExternal :: CopyMetaData -> FilePath -> FilePath -> IO Bool copyFileExternal meta src dest = do -- Delete any existing dest file because an unwritable file
Utility/DottedVersion.hs view
@@ -18,7 +18,10 @@ compare (DottedVersion _ x) (DottedVersion _ y) = compare x y instance Show DottedVersion where- show (DottedVersion s _) = s+ show = fromDottedVersion++fromDottedVersion :: DottedVersion -> String+fromDottedVersion (DottedVersion s _) = s {- To compare dotted versions like 1.7.7 and 1.8, they are normalized to - a somewhat arbitrary integer representation. -}
Utility/InodeCache.hs view
@@ -170,7 +170,9 @@ toInodeCache :: TSDelta -> FilePath -> FileStatus -> IO (Maybe InodeCache) toInodeCache (TSDelta getdelta) f s | isRegularFile s = do+#ifndef mingw32_HOST_OS delta <- getdelta+#endif sz <- getFileSize' f s #ifdef mingw32_HOST_OS mtime <- MTimeHighRes . utcTimeToPOSIXSeconds <$> getModificationTime f
Utility/Path/Max.hs view
@@ -10,8 +10,6 @@ module Utility.Path.Max where -import System.FilePath- #ifndef mingw32_HOST_OS import Utility.Exception import System.Posix.Files
doc/git-annex-add.mdwn view
@@ -22,9 +22,8 @@ Large files are added to the annex in locked form, which prevents further modification of their content unless unlocked by [[git-annex-unlock]](1). (This is not the case however when a repository is in a filesystem not-supporting symlinks, or is in direct mode.)-To add a file to the annex in unlocked form, `git add` can be used instead -(that only works in repository v7 or higher).+supporting symlinks.)+To add a file to the annex in unlocked form, `git add` can be used instead. This command can also be used to add symbolic links, both symlinks to annexed content, and other symlinks.
doc/git-annex-adjust.mdwn view
@@ -34,8 +34,6 @@ as necessary (eg for `--hide-missing`), and will also propagate commits back to the original branch. -This command can only be used in a v7 git-annex repository.- # OPTIONS * `--unlock`
doc/git-annex-contentlocation.mdwn view
@@ -12,10 +12,6 @@ of a key. The filename is output to stdout. If the key's content is not present in the local repository, nothing is output, and it exits nonzero. -Note that in direct mode, the file will typically be in the git work-tree, and while its content should correspond to the key, the file-could become modified at any time after git-annex checks it.- # OPTIONS * `--batch`
doc/git-annex-direct.mdwn view
@@ -1,6 +1,6 @@ # NAME -git-annex direct - switch repository to direct mode+git-annex direct - switch repository to direct mode (deprecated) # SYNOPSIS @@ -8,28 +8,15 @@ # DESCRIPTION -Switches a repository to use direct mode, where rather than symlinks to-files, the files are directly present in the repository.- -As part of the switch to direct mode, any changed files will be committed.--Note that git commands that operate on the work tree will refuse to-run in direct mode repositories. Use `git annex proxy` to safely run such-commands.--Note that the direct mode/indirect mode distinction is removed in v7-git-annex repositories. In such a repository, you can-use [[git-annex-unlock]](1) to make a file's content be directly present.-You can also use [[git-annex-adjust]](1) to enter a branch where all-annexed files are unlocked, which is similar to the old direct mode.+This used to switch a repository to use direct mode.+But direct mode is no longer used; git-annex automatically converts+direct mode repositories to v7 adjusted unlocked branches. # SEE ALSO [[git-annex]](1) [[git-annex-indirect]](1)--[[git-annex-unlock]](1) [[git-annex-adjust]](1)
doc/git-annex-examinekey.mdwn view
@@ -45,8 +45,7 @@ # EXAMPLES -The location a key's value is stored (in indirect mode)-can be looked up by running:+The location where the content of a key is stored can be looked up by running: git annex examinekey $KEY --format='.git/annex/objects/${hashdirmixed}${key}/${key}'
doc/git-annex-indirect.mdwn view
@@ -1,6 +1,6 @@ # NAME -git-annex indirect - switch repository to indirect mode+git-annex indirect - switch repository to indirect mode (deprecated) # SYNOPSIS @@ -8,11 +8,11 @@ # DESCRIPTION -Switches a repository back from direct mode to the default, indirect-mode.+This command was used to switch a repository back from direct mode+indirect mode. -Note that the direct mode/indirect mode distinction is removed in v7-git-annex repositories.+Now git-annex automatically converts direct mode repositories to v7+with adjusted unlocked branches, so this command does nothing. # SEE ALSO
doc/git-annex-pre-commit.mdwn view
@@ -17,9 +17,6 @@ When in a view, updates metadata to reflect changes made to files in the view. -When in a repository that has not been upgraded to v7, -also handles injecting changes to unlocked files into the annex. - # SEE ALSO [[git-annex]](1)
doc/git-annex-proxy.mdwn view
@@ -1,6 +1,6 @@ # NAME -git-annex proxy - safely bypass direct mode guard+git-annex proxy - safely bypass direct mode guard (deprecated) # SYNOPSIS @@ -8,36 +8,9 @@ # DESCRIPTION -Only useful in a direct mode repository, this runs the specified git-command with a temporary work tree, and updates the working tree to-reflect any changes staged or committed by the git command.--For example, to revert the most recent change that was committed-to the repository:-- git annex proxy -- git revert HEAD- -To check out a past version of the repository:-- git annex proxy -- git checkout HEAD^^- -To rename a directory:-- git annex proxy -- git mv mydir newname--To commit the changes to a specific file, first use git annex add to-stage the changes in the index, and then proxy a commit:-- git annex add myfile- git annex proxy -- git commit myfile -m foo--The temporary work tree that the git command is run in is set up by-checking out all files that are in the index, and copying (or hard linking)-any unstaged files from the real work tree. Since the git command is run-using this temporary work tree, it won't see eg, local modifications to-files. So, it probably is not useful to proxy a command like "git add".-However, you can use the proxy with any git command you like, as long as-you think about how it will interact with the temporary work tree.+This command was for use in a direct mode repository, and such +repositories are automatically updated to use an adjusted unlocked branch.+So, there's no reason to use this command any longer. # SEE ALSO
doc/git-annex-status.mdwn view
@@ -14,8 +14,6 @@ Show files that are not checked into git (?), deleted (D), modified (M), added but not committed (A), and type changed/unlocked (T). -Particularly useful in direct mode.- # OPTIONS * `--ignore-submodules=when`
doc/git-annex-unlock.mdwn view
@@ -11,24 +11,26 @@ Normally, the content of annexed files is protected from being changed. Unlocking an annexed file allows it to be modified. This replaces the symlink for each specified file with the file's content.-You can then modify it and `git annex add` (or `git commit`) to save your-changes. -In v5 repositories, unlocking a file is local-to the repository, and is temporary. In v7 repositories, unlocking a file-changes how it is stored in the git repository (from a symlink to a pointer-file), so you can commit it like any other change. Also in v7, you-can use `git add` to add a file to the annex in unlocked form. This allows-workflows where a file starts out unlocked, is modified as necessary, and-is locked once it reaches its final version.+Unlocking a file changes how it is stored in the git repository (from a+symlink to a pointer file), so this command will make a change that you+can commit. -Normally, unlocking a file requires a copy to be made of its content,-so that its original content is preserved, while the copy can be modified.-To use less space, annex.thin can be set to true; this makes a hard link-to the content be made instead of a copy. (Only when supported by the file-system, and only in v7 and higher.) While this can save considerable-disk space, any modification made to a file will cause the old version of the-file to be lost from the local repository. So, enable annex.thin with care.+The content of an unlocked file is still stored in git-annex, not git, +and when you commit modifications to the file, the modifications will also+be stored in git-annex, with only the pointer file stored in git.++If you use `git add` to add a file, it will be added in unlocked form from+the beginning. This allows workflows where a file starts out unlocked, is+modified as necessary, and is locked once it reaches its final version.++Normally, unlocking a file requires a copy to be made of its content, so+that its original content is preserved, while the copy can be modified. To+use less space, annex.thin can be set to true; this makes a hard link to+the content be made instead of a copy. (Only when supported by the file+system.) While this can save considerable disk space, any modification made+to a file will cause the old version of the file to be lost from the local+repository. So, enable annex.thin with care. # OPTIONS
doc/git-annex-upgrade.mdwn view
@@ -1,6 +1,6 @@ # NAME -git-annex upgrade - upgrade repository layout+git-annex upgrade - upgrade repository # SYNOPSIS @@ -8,13 +8,16 @@ # DESCRIPTION -Upgrades the repository to current layout.+Upgrades the repository. Each git-annex repository has an annex.version in its git configuration,-that indicates the repository version. If git-annex changes to a new-layout, you must upgrade the repository before git-annex can be used in it.+that indicates the repository version. When an old repository version+becomes deprecated, git-annex will automatically upgrade it+(unless annex.autoupgraderepository is set to false). To manually upgrade,+you can use this command. -To see version information, run `git annex version`. +Sometimes there's a newer repository version that is not the default yet,+and then you can use this command to upgrade to it. Currently, git-annex supports upgrades all the way back to version 0, which was only used by its author. It's expected that git-annex will always
doc/git-annex.mdwn view
@@ -100,7 +100,7 @@ * `status [path ...]` Similar to `git status --short`, displays the status of the files in the- working tree. Particularly useful in direct mode.+ working tree. See [[git-annex-status]](1) for details. @@ -313,26 +313,25 @@ See [[git-annex-vicfg]](1) for details. +* `adjust`++ Switches a repository to use an adjusted branch, which can automatically+ unlock all files, etc.+ + See [[git-annex-adjust]](1) for details.+ * `direct` - Switches a repository to use direct mode, where rather than symlinks to- files, the files are directly present in the repository.+ Switches a repository to use direct mode. (deprecated) See [[git-annex-direct]](1) for details. * `indirect` - Switches a repository back from direct mode to the default, indirect mode.+ Switches a repository to use indirect mode. (deprecated) See [[git-annex-indirect]](1) for details. -* `adjust`-- Switches a repository to use an adjusted branch, which can automatically- unlock all files, etc.- - See [[git-annex-adjust]](1) for details.- # REPOSITORY MAINTENANCE COMMANDS * `fsck [path ...]`@@ -384,7 +383,7 @@ * `upgrade` - Upgrades the repository to current layout.+ Upgrades the repository. See [[git-annex-upgrade]](1) for details. @@ -665,20 +664,6 @@ See [[git-annex-rekey]](1) for details. -* `findref [ref]`-- Lists files in a git ref. (deprecated)- - See [[git-annex-findref]](1) for details.--* `proxy -- git cmd [options]`-- Only useful in a direct mode repository, this runs the specified git- command with a temporary work tree, and updates the working tree to- reflect any changes staged or committed by the git command.- - See [[git-annex-proxy]](1) for details.- * `resolvemerge` Resolves a conflicted merge, by adding both conflicting versions of the@@ -708,6 +693,18 @@ See [[git-annex-remotedaemon]](1) for details. +* `findref [ref]`++ Lists files in a git ref. (deprecated)+ + See [[git-annex-findref]](1) for details.++* `proxy -- git cmd [options]`++ Bypass direct mode guard. (deprecated)+ + See [[git-annex-proxy]](1) for details.+ # TESTING COMMANDS * `test`@@ -839,10 +836,9 @@ Overrides git configuration settings. May be specified multiple times. -# CONFIGURATION VIA .git/config+# CONFIGURATION Like other git commands, git-annex is configured via `.git/config`.-Here are all the supported configuration settings. * `annex.uuid` @@ -911,7 +907,7 @@ Set to true to make commands like `git-annex add` that add files to the repository add them in unlocked form. The default is to add files in- locked form. This only has effect in v7 repositories.+ locked form. When a repository has core.symlinks set to false, it implicitly sets annex.addunlocked to true.@@ -1047,55 +1043,6 @@ And when multiple files in the work tree have the same content, only one of them gets hard linked to the annex. -* `annex.delayadd`-- Makes the watch and assistant commands delay for the specified number of- seconds before adding a newly created file to the annex. Normally this- is not needed, because they already wait for all writers of the file- to close it. On Mac OSX, when not using direct mode this defaults to- 1 second, to work around a bad interaction with software there.--* `annex.expireunused`-- Controls what the assistant does about unused file contents- that are stored in the repository.-- The default is `false`, which causes- all old and unused file contents to be retained, unless the assistant- is able to move them to some other repository (such as a backup repository).-- Can be set to a time specification, like "7d" or "1m", and then- file contents that have been known to be unused for a week or a- month will be deleted.--* `annex.fscknudge`-- When set to false, prevents the webapp from reminding you when using- repositories that lack consistency checks.--* `annex.autoupgrade`-- When set to ask (the default), the webapp will check for new versions- and prompt if they should be upgraded to. When set to true, automatically- upgrades without prompting (on some supported platforms). When set to- false, disables any upgrade checking.-- Note that upgrade checking is only done when git-annex is installed- from one of the prebuilt images from its website. This does not- bypass e.g., a Linux distribution's own upgrade handling code.-- This setting also controls whether to restart the git-annex assistant- when the git-annex binary is detected to have changed. That is useful- no matter how you installed git-annex.--* `annex.autocommit`-- Set to false to prevent the git-annex assistant and git-annex sync- from automatically committing changes to files in the repository.-- To configure the behavior in all clones of the repository,- this can be set in [[git-annex-config]].- * `annex.resolvemerge` Set to false to prevent merge conflicts in the checked out branch@@ -1113,33 +1060,26 @@ To configure the behavior in all clones of the repository, this can be set in [[git-annex-config]]. -* `annex.startupscan`-- Set to false to prevent the git-annex assistant from scanning the- repository for new and changed files on startup. This will prevent it- from noticing changes that were made while it was not running, but can be- a useful performance tweak for a large repository.--* `annex.listen`-- Configures which address the webapp listens on. The default is localhost.- Can be either an IP address, or a hostname that resolves to the desired- address.- * `annex.debug` Set to true to enable debug logging by default. * `annex.version` - Automatically maintained, and used to automate upgrades between versions.+ The current version of the git-annex repository. This is+ maintained by git-annex and should never be manually changed. -* `annex.direct`+* `annex.autoupgraderepository` - Set to true when the repository is in direct mode. Should not be set- manually; use the "git annex direct" and "git annex indirect" commands- instead.+ When an old git-annex repository version has become deprecated,+ git-annex will normally automatically upgrade the repository to+ the new version. + If this is set to false, git-annex won't automatically upgrade the+ repository. Instead it will exit with an error message. You can run+ `git annex upgrade` yourself when you are ready to upgrade the+ repository.+ * `annex.crippledfilesystem` Set to true if the repository is on a crippled filesystem, such as FAT,@@ -1182,6 +1122,27 @@ be extracted and decrypted each time git-annex needs to access the remote. +* `annex.secure-erase-command`++ This can be set to a command that should be run whenever git-annex+ removes the content of a file from the repository.++ In the command line, %file is replaced with the file that should be+ erased.++ For example, to use the wipe command, set it to `wipe -f %file`.++* `annex.tune.objecthash1`, `annex.tune.objecthashlower`, `annex.tune.branchhash1`++ These can be passed to `git annex init` to tune the repository.+ They cannot be safely changed in a running repository and should never be+ set in global git configuration.+ For details, see <https://git-annex.branchable.com/tuning/>.++# CONFIGURATION OF REMOTES++Remotes are configured using these settings in `.git/config`.+ * `remote.<name>.annex-cost` When determining which repository to@@ -1417,6 +1378,91 @@ Default options to use if a remote does not have more specific options as described above. +* `remote.<name>.annex-rsyncurl`++ Used by rsync special remotes, this configures+ the location of the rsync repository to use. Normally this is automatically+ set up by `git annex initremote`, but you can change it if needed.++* `remote.<name>.annex-buprepo`++ Used by bup special remotes, this configures+ the location of the bup repository to use. Normally this is automatically+ set up by `git annex initremote`, but you can change it if needed.++* `remote.<name>.annex-ddarrepo`++ Used by ddar special remotes, this configures+ the location of the ddar repository to use. Normally this is automatically+ set up by `git annex initremote`, but you can change it if needed.++* `remote.<name>.annex-directory`++ Used by directory special remotes, this configures+ the location of the directory where annexed files are stored for this+ remote. Normally this is automatically set up by `git annex initremote`,+ but you can change it if needed.++* `remote.<name>.annex-adb`++ Used to identify remotes on Android devices accessed via adb.+ Normally this is automatically set up by `git annex initremote`.++* `remote.<name>.annex-androiddirectory`++ Used by adb special remotes, this is the directory on the Android+ device where files are stored for this remote. Normally this is+ automatically set up by `git annex initremote`, but you can change+ it if needed.++* `remote.<name>.annex-androidserial`++ Used by adb special remotes, this is the serial number of the Android+ device used by the remote. Normally this is automatically set up by+ `git annex initremote`, but you can change it if needed, eg when+ upgrading to a new Android device.++* `remote.<name>.annex-s3`++ Used to identify Amazon S3 special remotes.+ Normally this is automatically set up by `git annex initremote`.++* `remote.<name>.annex-glacier`++ Used to identify Amazon Glacier special remotes.+ Normally this is automatically set up by `git annex initremote`.++* `remote.<name>.annex-webdav`++ Used to identify webdav special remotes.+ Normally this is automatically set up by `git annex initremote`.++* `remote.<name>.annex-tahoe`++ Used to identify tahoe special remotes.+ Points to the configuration directory for tahoe.++* `remote.<name>.annex-gcrypt`++ Used to identify gcrypt special remotes.+ Normally this is automatically set up by `git annex initremote`.++ It is set to "true" if this is a gcrypt remote.+ If the gcrypt remote is accessible over ssh and has git-annex-shell+ available to manage it, it's set to "shell".++* `remote.<name>.annex-git-lfs`++ Used to identify git-lfs special remotes.+ Normally this is automatically set up by `git annex initremote`.++ It is set to "true" if this is a git-lfs remote.++* `remote.<name>.annex-hooktype`, `remote.<name>.annex-externaltype`++ Used by hook special remotes and external special remotes to record+ the type of the remote.+ * `annex.web-options` Options to pass to curl when git-annex uses it to download urls@@ -1532,111 +1578,72 @@ It would be a good idea to check that it downloaded the file you expected, too. -* `remote.name.annex-security-allow-unverified-downloads`+* `remote.<name>.annex-security-allow-unverified-downloads` Per-remote configuration of annex.security.allow-unverified-downloads. -* `annex.secure-erase-command`-- This can be set to a command that should be run whenever git-annex- removes the content of a file from the repository.-- In the command line, %file is replaced with the file that should be- erased.-- For example, to use the wipe command, set it to `wipe -f %file`.--* `remote.<name>.annex-rsyncurl`-- Used by rsync special remotes, this configures- the location of the rsync repository to use. Normally this is automatically- set up by `git annex initremote`, but you can change it if needed.--* `remote.<name>.annex-buprepo`-- Used by bup special remotes, this configures- the location of the bup repository to use. Normally this is automatically- set up by `git annex initremote`, but you can change it if needed.--* `remote.<name>.annex-ddarrepo`-- Used by ddar special remotes, this configures- the location of the ddar repository to use. Normally this is automatically- set up by `git annex initremote`, but you can change it if needed.--* `remote.<name>.annex-directory`-- Used by directory special remotes, this configures- the location of the directory where annexed files are stored for this- remote. Normally this is automatically set up by `git annex initremote`,- but you can change it if needed.--* `remote.<name>.annex-adb`-- Used to identify remotes on Android devices accessed via adb.- Normally this is automatically set up by `git annex initremote`.--* `remote.<name>.annex-androiddirectory`-- Used by adb special remotes, this is the directory on the Android- device where files are stored for this remote. Normally this is- automatically set up by `git annex initremote`, but you can change- it if needed.--* `remote.<name>.annex-androidserial`+# CONFIGURATION OF ASSISTANT - Used by adb special remotes, this is the serial number of the Android- device used by the remote. Normally this is automatically set up by- `git annex initremote`, but you can change it if needed, eg when- upgrading to a new Android device.+* `annex.delayadd` -* `remote.<name>.annex-s3`+ Makes the watch and assistant commands delay for the specified number of+ seconds before adding a newly created file to the annex. Normally this+ is not needed, because they already wait for all writers of the file+ to close it. - Used to identify Amazon S3 special remotes.- Normally this is automatically set up by `git annex initremote`.+* `annex.expireunused` -* `remote.<name>.annex-glacier`+ Controls what the assistant does about unused file contents+ that are stored in the repository. - Used to identify Amazon Glacier special remotes.- Normally this is automatically set up by `git annex initremote`.+ The default is `false`, which causes+ all old and unused file contents to be retained, unless the assistant+ is able to move them to some other repository (such as a backup repository). -* `remote.<name>.annex-webdav`+ Can be set to a time specification, like "7d" or "1m", and then+ file contents that have been known to be unused for a week or a+ month will be deleted. - Used to identify webdav special remotes.- Normally this is automatically set up by `git annex initremote`.+* `annex.fscknudge` -* `remote.<name>.annex-tahoe`+ When set to false, prevents the webapp from reminding you when using+ repositories that lack consistency checks. - Used to identify tahoe special remotes.- Points to the configuration directory for tahoe.+* `annex.autoupgrade` -* `remote.<name>.annex-gcrypt`+ When set to ask (the default), the webapp will check for new versions+ and prompt if they should be upgraded to. When set to true, automatically+ upgrades without prompting (on some supported platforms). When set to+ false, disables any upgrade checking. - Used to identify gcrypt special remotes.- Normally this is automatically set up by `git annex initremote`.+ Note that upgrade checking is only done when git-annex is installed+ from one of the prebuilt images from its website. This does not+ bypass e.g., a Linux distribution's own upgrade handling code. - It is set to "true" if this is a gcrypt remote.- If the gcrypt remote is accessible over ssh and has git-annex-shell- available to manage it, it's set to "shell".+ This setting also controls whether to restart the git-annex assistant+ when the git-annex binary is detected to have changed. That is useful+ no matter how you installed git-annex. -* `remote.<name>.annex-git-lfs`+* `annex.autocommit` - Used to identify git-lfs special remotes.- Normally this is automatically set up by `git annex initremote`.+ Set to false to prevent the git-annex assistant and git-annex sync+ from automatically committing changes to files in the repository. - It is set to "true" if this is a git-lfs remote.+ To configure the behavior in all clones of the repository,+ this can be set in [[git-annex-config]]. -* `remote.<name>.annex-hooktype`, `remote.<name>.annex-externaltype`+* `annex.startupscan` - Used by hook special remotes and external special remotes to record- the type of the remote.+ Set to false to prevent the git-annex assistant from scanning the+ repository for new and changed files on startup. This will prevent it+ from noticing changes that were made while it was not running, but can be+ a useful performance tweak for a large repository. -* `annex.tune.objecthash1`, `annex.tune.objecthashlower`, `annex.tune.branchhash1`+* `annex.listen` - These can be passed to `git annex init` to tune the repository.- They cannot be safely changed in a running repository and should never be- set in global git configuration.- For details, see <https://git-annex.branchable.com/tuning/>.+ Configures which address the webapp listens on. The default is localhost.+ Can be either an IP address, or a hostname that resolves to the desired+ address. # CONFIGURATION VIA .gitattributes
git-annex.cabal view
@@ -1,5 +1,5 @@ Name: git-annex-Version: 7.20190819+Version: 7.20190912 Cabal-Version: >= 1.8 License: AGPL-3 Maintainer: Joey Hess <id@joeyh.name>@@ -577,7 +577,7 @@ Assistant.WebApp.RepoList Assistant.WebApp.SideBar Assistant.WebApp.Types- Annex.MakeRepo+ Assistant.MakeRepo Utility.Yesod Utility.WebApp @@ -618,13 +618,11 @@ Annex.Common Annex.Concurrent Annex.Content- Annex.Content.Direct Annex.Content.LowLevel Annex.Content.PointerFile Annex.CurrentBranch Annex.Difference Annex.DirHashes- Annex.Direct Annex.Drop Annex.Environment Annex.Export@@ -1011,6 +1009,7 @@ Upgrade.V3 Upgrade.V4 Upgrade.V5+ Upgrade.V5.Direct Upgrade.V6 Utility.Aeson Utility.Android