packages feed

git-annex 8.20200226 → 8.20200309

raw patch · 69 files changed

+679/−383 lines, 69 files

Files

Annex.hs view
@@ -1,6 +1,6 @@ {- git-annex monad  -- - Copyright 2010-2018 Joey Hess <id@joeyh.name>+ - Copyright 2010-2020 Joey Hess <id@joeyh.name>  -  - Licensed under the GNU AGPL version 3 or higher.  -}@@ -28,7 +28,7 @@ 	fromRepo, 	calcRepo, 	getGitConfig,-	changeGitConfig,+	overrideGitConfig, 	changeGitRepo, 	adjustGitRepo, 	getRemoteGitConfig,@@ -104,6 +104,7 @@ 	{ repo :: Git.Repo 	, repoadjustment :: (Git.Repo -> IO Git.Repo) 	, gitconfig :: GitConfig+	, gitconfigadjustment :: (GitConfig -> GitConfig) 	, gitremotes :: Maybe [Git.Repo] 	, backend :: Maybe (BackendA Annex) 	, remotes :: [Types.Remote.RemoteA Annex]@@ -161,6 +162,7 @@ 		{ repo = r 		, repoadjustment = return 		, gitconfig = c+		, gitconfigadjustment = id 		, gitremotes = Nothing 		, backend = Nothing 		, remotes = []@@ -314,19 +316,13 @@ getGitConfig :: Annex GitConfig getGitConfig = getState gitconfig -{- Modifies a GitConfig setting. -}-changeGitConfig :: (GitConfig -> GitConfig) -> Annex ()-changeGitConfig a = changeState $ \s -> s { gitconfig = a (gitconfig s) }--{- Changing the git Repo data also involves re-extracting its GitConfig. -}-changeGitRepo :: Git.Repo -> Annex ()-changeGitRepo r = do-	adjuster <- getState repoadjustment-	r' <- liftIO $ adjuster r-	changeState $ \s -> s-		{ repo = r'-		, gitconfig = extractGitConfig FromGitConfig r'-		}+{- Overrides a GitConfig setting. The modification persists across+ - reloads of the repo's config. -}+overrideGitConfig :: (GitConfig -> GitConfig) -> Annex ()+overrideGitConfig f = changeState $ \s -> s+	{ gitconfigadjustment = gitconfigadjustment s . f+	, gitconfig = f (gitconfig s)+	}  {- Adds an adjustment to the Repo data. Adjustments persist across reloads  - of the repo's config. -}@@ -334,6 +330,18 @@ adjustGitRepo a = do 	changeState $ \s -> s { repoadjustment = \r -> repoadjustment s r >>= a } 	changeGitRepo =<< gitRepo++{- Changing the git Repo data also involves re-extracting its GitConfig. -}+changeGitRepo :: Git.Repo -> Annex ()+changeGitRepo r = do+	repoadjuster <- getState repoadjustment+	gitconfigadjuster <- getState gitconfigadjustment+	r' <- liftIO $ repoadjuster r+	changeState $ \s -> s+		{ repo = r'+		, gitconfig = gitconfigadjuster $+			extractGitConfig FromGitConfig r'+		}  {- Gets the RemoteGitConfig from a remote, given the Git.Repo for that  - remote. -}
Annex/AdjustedBranch.hs view
@@ -57,6 +57,7 @@ import Annex.GitOverlay import Utility.Tmp.Dir import Utility.CopyFile+import Utility.Directory import qualified Database.Keys import Config @@ -375,10 +376,10 @@ 	 - index file is currently locked.) 	 -} 	changestomerge (Just updatedorig) = withOtherTmp $ \othertmpdir -> do-		tmpwt <- fromRepo gitAnnexMergeDir 		git_dir <- fromRawFilePath <$> fromRepo Git.localGitDir+		tmpwt <- fromRepo gitAnnexMergeDir 		withTmpDirIn othertmpdir "git" $ \tmpgit -> withWorkTreeRelated tmpgit $-			withemptydir tmpwt $ withWorkTree tmpwt $ do+			withemptydir git_dir tmpwt $ withWorkTree tmpwt $ do 				liftIO $ writeFile (tmpgit </> "HEAD") (fromRef updatedorig) 				-- Copy in refs and packed-refs, to work 				-- around bug in git 2.13.0, which@@ -390,7 +391,7 @@ 					whenM (doesFileExist src) $ do 						dest <- relPathDirToFile git_dir src 						let dest' = tmpgit </> dest-						createDirectoryIfMissing True (takeDirectory dest')+						createDirectoryUnder git_dir (takeDirectory dest') 						void $ createLinkOrCopy src dest' 				-- This reset makes git merge not care 				-- that the work tree is empty; otherwise@@ -411,12 +412,12 @@ 					else return $ return False 	changestomerge Nothing = return $ return False 	-	withemptydir d a = bracketIO setup cleanup (const a)+	withemptydir git_dir d a = bracketIO setup cleanup (const a) 	  where 		setup = do 			whenM (doesDirectoryExist d) $ 				removeDirectoryRecursive d-			createDirectoryIfMissing True d+			createDirectoryUnder git_dir d 		cleanup _ = removeDirectoryRecursive d  	{- A merge commit has been made between the basisbranch and 
Annex/AutoMerge.hs view
@@ -208,7 +208,7 @@ 		stageSymlink dest' =<< hashSymlink l  	replacewithsymlink dest link = withworktree dest $ \f ->-		replaceFile f $ makeGitLink link . toRawFilePath+		replaceWorkTreeFile f $ makeGitLink link . toRawFilePath  	makepointer key dest destmode = do 		unless inoverlay $ @@ -256,7 +256,7 @@ 				, case selectwant' (LsFiles.unmergedSha u) of 					Nothing -> noop 					Just sha -> withworktree item $ \f -> -						replaceFile f $ \tmp -> do+						replaceWorkTreeFile f $ \tmp -> do 							c <- catObject sha 							liftIO $ L.writeFile tmp c 				)
Annex/ChangedRefs.hs view
@@ -76,8 +76,9 @@ 	chan <- liftIO $ newTBMChanIO 100 	 	g <- gitRepo-	let refdir = fromRawFilePath (Git.localGitDir g) </> "refs"-	liftIO $ createDirectoryIfMissing True refdir+	let gittop = fromRawFilePath (Git.localGitDir g)+	let refdir = gittop </> "refs"+	liftIO $ createDirectoryUnder gittop refdir  	let notifyhook = Just $ notifyHook chan 	let hooks = mkWatchHooks
Annex/Content.hs view
@@ -879,8 +879,7 @@ 		liftIO $ writeFile obj "" 		setAnnexFilePerm obj 	let tmpdir = gitAnnexTmpWorkDir obj-	liftIO $ createDirectoryIfMissing True tmpdir-	setAnnexDirPerm tmpdir+	createAnnexDirectory tmpdir 	res <- action tmpdir 	case res of 		Just _ -> liftIO $ removeDirectoryRecursive tmpdir
Annex/Content/PointerFile.hs view
@@ -39,7 +39,7 @@ 		let f' = fromRawFilePath f 		destmode <- liftIO $ catchMaybeIO $ fileMode <$> getFileStatus f' 		liftIO $ nukeFile f'-		(ic, populated) <- replaceFile f' $ \tmp -> do+		(ic, populated) <- replaceWorkTreeFile f' $ \tmp -> do 			let tmp' = toRawFilePath tmp 			ok <- linkOrCopy k (fromRawFilePath obj) tmp destmode >>= \case 				Just _ -> thawContent tmp >> return True@@ -62,7 +62,7 @@ 	let mode = fmap fileMode st 	secureErase file' 	liftIO $ nukeFile file'-	ic <- replaceFile file' $ \tmp -> do+	ic <- replaceWorkTreeFile file' $ \tmp -> do 		liftIO $ writePointerFile (toRawFilePath tmp) key mode #if ! defined(mingw32_HOST_OS) 		-- Don't advance mtime; this avoids unncessary re-smudging
Annex/Fixup.hs view
@@ -1,6 +1,6 @@ {- git-annex repository fixups  -- - Copyright 2013-2019 Joey Hess <id@joeyh.name>+ - Copyright 2013-2020 Joey Hess <id@joeyh.name>  -  - Licensed under the GNU AGPL version 3 or higher.  -}@@ -12,8 +12,6 @@ import Git.Types import Git.Config import Types.GitConfig-import Config.Files-import qualified Git import Utility.Path import Utility.SafeCommand import Utility.Directory@@ -83,27 +81,24 @@  - also converted to a symlink so links to .git/annex will work.   -   - When the filesystem doesn't support symlinks, we cannot make .git- - into a symlink. But we don't need too, since the repo will use direct- - mode.+ - into a symlink. But we don't need too, since the repo will use adjusted+ - unlocked branches.  -- - Before making any changes, check if there's a .noannex file- - in the repo. If that file will prevent git-annex from being used,- - there's no need to fix up the repository.+ - Don't do any of this if the repo has not been initialized for git-annex+ - use yet.  -} fixupUnusualRepos :: Repo -> GitConfig -> IO Repo fixupUnusualRepos r@(Repo { location = l@(Local { worktree = Just w, gitdir = d }) }) c-	| needsSubmoduleFixup r = ifM notnoannex-		( do-			when (coreSymlinks c) $-				(replacedotgit >> unsetcoreworktree)-					`catchNonAsync` \_e -> hPutStrLn stderr-						"warning: unable to convert submodule to form that will work with git-annex"-			return $ r'-				{ config = M.delete "core.worktree" (config r)-				}-		, return r-		)-	| otherwise = ifM (needsGitLinkFixup r <&&> notnoannex)+	| isNothing (annexVersion c) = return r+	| needsSubmoduleFixup r = do+		when (coreSymlinks c) $+			(replacedotgit >> unsetcoreworktree)+				`catchNonAsync` \_e -> hPutStrLn stderr+					"warning: unable to convert submodule to form that will work with git-annex"+		return $ r'+			{ config = M.delete "core.worktree" (config r)+			}+	| otherwise = ifM (needsGitLinkFixup r) 		( do 			when (coreSymlinks c) $ 				(replacedotgit >> worktreefixup)@@ -144,8 +139,6 @@ 	r' 		| coreSymlinks c = r { location = l { gitdir = dotgit } } 		| otherwise = r--	notnoannex = isNothing <$> noAnnexFileContent (fmap fromRawFilePath (Git.repoWorkTree r)) fixupUnusualRepos r _ = return r  needsSubmoduleFixup :: Repo -> Bool
Annex/Ingest.hs view
@@ -274,7 +274,7 @@ makeLink :: FilePath -> Key -> Maybe InodeCache -> Annex String makeLink file key mcache = flip catchNonAsync (restoreFile file key) $ do 	l <- calcRepo $ gitAnnexLink file key-	replaceFile file $ makeAnnexLink l . toRawFilePath+	replaceWorkTreeFile file $ makeAnnexLink l . toRawFilePath  	-- touch symlink to have same time as the original file, 	-- as provided in the InodeCache
Annex/Init.hs view
@@ -34,6 +34,7 @@ import Annex.Difference import Annex.UUID import Annex.WorkTree+import Annex.Fixup import Config import Config.Files import Config.Smudge@@ -129,6 +130,7 @@ 				) 	propigateSecureHashesOnly 	createInodeSentinalFile False+	fixupUnusualReposAfterInit  uninitialize :: Annex () uninitialize = do@@ -280,3 +282,8 @@ propigateSecureHashesOnly = 	maybe noop (setConfig "annex.securehashesonly" . fromConfigValue) 		=<< getGlobalConfig "annex.securehashesonly"++fixupUnusualReposAfterInit :: Annex ()+fixupUnusualReposAfterInit = do+	gc <- Annex.getGitConfig+	void $ inRepo $ \r -> fixupUnusualRepos r gc
Annex/Perms.hs view
@@ -1,6 +1,6 @@ {- git-annex file permissions  -- - Copyright 2012 Joey Hess <id@joeyh.name>+ - Copyright 2012-2020 Joey Hess <id@joeyh.name>  -  - Licensed under the GNU AGPL version 3 or higher.  -}@@ -11,6 +11,7 @@ 	setAnnexDirPerm, 	annexFileMode, 	createAnnexDirectory,+	createWorkTreeDirectory, 	noUmask, 	freezeContent, 	isContentWritePermOk,@@ -25,6 +26,7 @@  import Annex.Common import Utility.FileMode+import Git import Git.ConfigTypes import qualified Annex import Config@@ -65,22 +67,31 @@ 	go _ = stdFileMode 	sharedmode = combineModes groupSharedModes -{- Creates a directory inside the gitAnnexDir, including any parent- - directories. Makes directories with appropriate permissions. -}+{- Creates a directory inside the gitAnnexDir, creating any parent+ - directories up to and including the gitAnnexDir.+ - Makes directories with appropriate permissions. -} createAnnexDirectory :: FilePath -> Annex ()-createAnnexDirectory dir = walk dir [] =<< top+createAnnexDirectory dir = do+	top <- parentDir . fromRawFilePath <$> fromRepo gitAnnexDir+	createDirectoryUnder' top dir createdir   where-	top = parentDir . fromRawFilePath <$> fromRepo gitAnnexDir-	walk d below stop-		| d `equalFilePath` stop = done-		| otherwise = ifM (liftIO $ doesDirectoryExist d)-			( done-			, walk (parentDir d) (d:below) stop-			)-	  where-		done = forM_ below $ \p -> do-			liftIO $ createDirectoryIfMissing True p-			setAnnexDirPerm p+	createdir p = do+		liftIO $ createDirectory p+		setAnnexDirPerm p++{- Create a directory in the git work tree, creating any parent+ - directories up to the top of the work tree.+ -+ - Uses default permissions.+ -}+createWorkTreeDirectory :: FilePath -> Annex ()+createWorkTreeDirectory dir = do+	fromRepo repoWorkTree >>= liftIO . \case+		Just wt -> createDirectoryUnder (fromRawFilePath wt) dir+		-- Should never happen, but let whatever tries to write+		-- to the directory be what throws an exception, as that+		-- will be clearer than an exception from here.+		Nothing -> noop  {- Normally, blocks writing to an annexed file, and modifies file  - permissions to allow reading it.
Annex/ReplaceFile.hs view
@@ -1,21 +1,42 @@ {- git-annex file replacing  -- - Copyright 2013-2015 Joey Hess <id@joeyh.name>+ - Copyright 2013-2020 Joey Hess <id@joeyh.name>  -  - Licensed under the GNU AGPL version 3 or higher.  -}  {-# LANGUAGE CPP #-} -module Annex.ReplaceFile where+module Annex.ReplaceFile (+	replaceGitAnnexDirFile,+	replaceGitDirFile,+	replaceWorkTreeFile,+	replaceFile,+) where  import Annex.Common import Annex.Tmp+import Annex.Perms+import Git import Utility.Tmp.Dir #ifndef mingw32_HOST_OS import Utility.Path.Max #endif +{- replaceFile on a file located inside the gitAnnexDir. -}+replaceGitAnnexDirFile :: FilePath -> (FilePath -> Annex a) -> Annex a+replaceGitAnnexDirFile = replaceFile createAnnexDirectory++{- replaceFile on a file located inside the .git directory. -}+replaceGitDirFile :: FilePath -> (FilePath -> Annex a) -> Annex a+replaceGitDirFile = replaceFile $ \dir -> do+	top <- fromRawFilePath <$> fromRepo localGitDir+	liftIO $ createDirectoryUnder top dir++{- replaceFile on a worktree file. -}+replaceWorkTreeFile :: FilePath -> (FilePath -> Annex a) -> Annex a+replaceWorkTreeFile = replaceFile createWorkTreeDirectory+ {- Replaces a possibly already existing file with a new version,   - atomically, by running an action.  - @@ -27,9 +48,12 @@  - will be deleted, and the existing file will be preserved.  -  - Throws an IO exception when it was unable to replace the file.+ -+ - The createdirectory action is only run when moving the file into place+ - fails, and can create any parent directory structure needed.  -}-replaceFile :: FilePath -> (FilePath -> Annex a) -> Annex a-replaceFile file action = withOtherTmp $ \othertmpdir -> do+replaceFile :: (FilePath -> Annex ()) -> FilePath -> (FilePath -> Annex a) -> Annex a+replaceFile createdirectory file action = withOtherTmp $ \othertmpdir -> do #ifndef mingw32_HOST_OS 	-- Use part of the filename as the template for the temp 	-- directory. This does not need to be unique, but it@@ -44,13 +68,13 @@ 	withTmpDirIn othertmpdir basetmp $ \tmpdir -> do 		let tmpfile = tmpdir </> basetmp 		r <- action tmpfile-		liftIO $ replaceFileFrom tmpfile file+		replaceFileFrom tmpfile file createdirectory 		return r -replaceFileFrom :: FilePath -> FilePath -> IO ()-replaceFileFrom src dest = go `catchIO` fallback+replaceFileFrom :: FilePath -> FilePath -> (FilePath -> Annex ()) -> Annex ()+replaceFileFrom src dest createdirectory = go `catchIO` fallback   where-	go = moveFile src dest+	go = liftIO $ moveFile src dest 	fallback _ = do-		createDirectoryIfMissing True $ parentDir dest+		createdirectory (parentDir dest) 		go
Annex/SpecialRemote/Config.hs view
@@ -16,7 +16,7 @@ import Types.UUID import Types.ProposedAccepted import Types.RemoteConfig-import Config+import Types.GitConfig import qualified Git.Config  import qualified Data.Map as M@@ -234,8 +234,12 @@ 	p Nothing _c = Right Nothing  yesNoParser :: RemoteConfigField -> Bool -> FieldDesc -> RemoteConfigFieldParser-yesNoParser f v fd = genParser yesNo f v fd+yesNoParser f v fd = genParser yesno f v fd 	(Just (ValueDesc "yes or no"))+  where+	yesno "yes" = Just True+	yesno "no" = Just False+	yesno _ = Nothing  trueFalseParser :: RemoteConfigField -> Bool -> FieldDesc -> RemoteConfigFieldParser trueFalseParser f v fd = genParser Git.Config.isTrueFalse f v fd
Annex/Ssh.hs view
@@ -154,8 +154,11 @@ sshSocketDirEnv :: String sshSocketDirEnv = "GIT_ANNEX_SSH_SOCKET_DIR" -{- ssh connection caching creates sockets, so will not work on a- - crippled filesystem. -}+{- Returns the directory where ssh connection caching sockets can be+ - stored.+ - + - The directory will be created if it does not exist.+ -} sshCacheDir :: Annex (Maybe FilePath) sshCacheDir = eitherToMaybe <$> sshCacheDir' @@ -169,7 +172,10 @@ 				Just tmpdir ->  					liftIO $ catchMsgIO $ 						usetmpdir tmpdir-			, Right <$> fromRepo gitAnnexSshDir +			, do+				d <- fromRepo gitAnnexSshDir+				createAnnexDirectory d+				return (Right d) 			) 		, return (Left "annex.sshcaching is not set to true") 		)@@ -221,7 +227,6 @@ 	-- Cleanup at shutdown. 	Annex.addCleanup SshCachingCleanup sshCleanup 	-	liftIO $ createDirectoryIfMissing True $ parentDir socketfile 	let socketlock = socket2lock socketfile  	Annex.getState Annex.concurrency >>= \case
Annex/UUID.hs view
@@ -102,9 +102,7 @@ 	storeUUID =<< liftIO genUUID  storeUUID :: UUID -> Annex ()-storeUUID u = do-	Annex.changeGitConfig $ \c -> c { annexUUID = u }-	storeUUIDIn configkeyUUID u+storeUUID = storeUUIDIn configkeyUUID  storeUUIDIn :: ConfigKey -> UUID -> Annex () storeUUIDIn configfield = setConfig configfield . fromUUID
Annex/WorkTree.hs view
@@ -100,7 +100,7 @@ 				Just k' | k' == k -> do 					destmode <- liftIO $ catchMaybeIO $ 						fileMode <$> R.getFileStatus f-					ic <- replaceFile (fromRawFilePath f) $ \tmp -> do+					ic <- replaceWorkTreeFile (fromRawFilePath f) $ \tmp -> do 						let tmp' = toRawFilePath tmp 						linkFromAnnex k tmp destmode >>= \case 							LinkAnnexOk -> 
Assistant.hs view
@@ -75,6 +75,7 @@ 	pidfile <- fromRepo gitAnnexPidFile 	logfile <- fromRepo gitAnnexLogFile 	liftIO $ debugM desc $ "logging to " ++ logfile+	createAnnexDirectory (parentDir pidfile) #ifndef mingw32_HOST_OS 	createAnnexDirectory (parentDir logfile) 	logfd <- liftIO $ handleToFd =<< openLog logfile
Assistant/Threads/Merger.hs view
@@ -26,8 +26,9 @@ mergeThread :: NamedThread mergeThread = namedThread "Merger" $ do 	g <- liftAnnex gitRepo-	let dir = fromRawFilePath (Git.localGitDir g) </> "refs"-	liftIO $ createDirectoryIfMissing True dir+	let gitd = fromRawFilePath (Git.localGitDir g)+	let dir = gitd </> "refs"+	liftIO $ createDirectoryUnder gitd dir 	let hook a = Just <$> asIO2 (runHandler a) 	changehook <- hook onChange 	errhook <- hook onErr
Assistant/Threads/TransferWatcher.hs view
@@ -15,6 +15,7 @@ import Utility.DirWatcher import Utility.DirWatcher.Types import qualified Remote+import Annex.Perms  import Control.Concurrent import qualified Data.Map as M@@ -24,7 +25,7 @@ transferWatcherThread :: NamedThread transferWatcherThread = namedThread "TransferWatcher" $ do 	dir <- liftAnnex $ gitAnnexTransferDir <$> gitRepo-	liftIO $ createDirectoryIfMissing True dir+	liftAnnex $ createAnnexDirectory dir 	let hook a = Just <$> asIO2 (runHandler a) 	addhook <- hook onAdd 	delhook <- hook onDel
Assistant/Threads/Watcher.hs view
@@ -300,7 +300,7 @@ 		if linktarget == Just link 			then ensurestaged (Just link) =<< getDaemonStatus 			else do-				liftAnnex $ replaceFile file $+				liftAnnex $ replaceWorkTreeFile file $ 					makeAnnexLink link . toRawFilePath 				addLink file link (Just key) 	-- other symlink, not git-annex
Assistant/WebApp/Configurators/Edit.hs view
@@ -41,6 +41,7 @@ import Types.Crypto import Utility.Gpg import Annex.UUID+import Annex.Perms import Assistant.Ssh import Config import Config.GitConfig@@ -246,9 +247,9 @@ 	repoconfig <- M.lookup (Remote.uuid r) <$> readRemoteLog 	case repoGroup cfg of 		RepoGroupStandard gr -> case associatedDirectory repoconfig gr of-			Just d -> inRepo $ \g ->-				createDirectoryIfMissing True $-					fromRawFilePath (Git.repoPath g) </> d+			Just d -> do+				top <- fromRawFilePath <$> fromRepo Git.repoPath+				createWorkTreeDirectory (top </> d) 			Nothing -> noop 		_ -> noop 
CHANGELOG view
@@ -1,3 +1,36 @@+git-annex (8.20200309) upstream; urgency=medium++  * Fix bug that caused unlocked annexed dotfiles to be added to git by the+    smudge filter when annex.dotfiles was not set.+  * Upgrade other repos than the current one by running git-annex upgrade+    inside them, which avoids problems with upgrade code making assumptions+    that the cwd will be inside the repo being upgraded. In particular,+    this fixes a problem where upgrading a v7 repo to v8 caused an ugly+    git error message.+  * Fix upgrade failure when a file has been deleted from the working tree.+  * Fix regression 1 month ago that prevented external special remotes from+    using GETCONFIG to query values like "name".+  * Improve behavior when a directory git-annex is writing to gets+    unmounted. Previously it could in some cases re-create the mount point+    and directory tree, and even write object contents to the wrong disk.+  * Don't ignore --debug when it is followed by -c.+  * whereis: If a remote fails to report on urls where a key+    is located, display a warning, rather than giving up and not displaying+    any information.+  * When external special remotes fail but neglect to provide an error+    message, say what request failed, which is better than displaying an+    empty error message to the user.+  * git-annex config: Only allow configs be set that are ones git-annex+    actually supports reading from repo-global config, to avoid confusion.+  * Avoid converting .git file in a worktree or submodule to a symlink+    when the repository is not a git-annex repository.+  * Linux standalone: Use md5sum to shorten paths in .cache/git-annex/locales+  * Fix build with ghc 8.8 (MonadFail)+    Thanks, Peter Simons+  * stack.yaml: Updated to lts-14.27.++ -- Joey Hess <id@joeyh.name>  Mon, 09 Mar 2020 17:04:08 -0400+ git-annex (8.20200226) upstream; urgency=medium    * New v8 repository version.@@ -42,6 +75,7 @@     on those remotes without encrypting it.     If your remotes are affected, you will want to make sure to delete     any content that git-annex has stored on them that is not encrypted!+  * initremote: Fix regression in parsing the exporttree= parameter.   * info: Fix display of the encryption value.     (Some debugging junk had crept in.)   * Bugfix to getting content from an export remote with -J, when the
CmdLine/GitAnnex/Options.hs view
@@ -9,6 +9,7 @@  module CmdLine.GitAnnex.Options where +import Control.Monad.Fail as Fail (MonadFail(..)) import Options.Applicative import qualified Data.Map as M @@ -215,8 +216,8 @@ 	<> help "operate on all versions of all files" 	) -parseKey :: Monad m => String -> m Key-parseKey = maybe (fail "invalid key") return . deserializeKey+parseKey :: MonadFail m => String -> m Key+parseKey = maybe (Fail.fail "invalid key") return . deserializeKey  -- Options to match properties of annexed files. annexedMatchingOptions :: [GlobalOption]
CmdLine/Option.hs view
@@ -59,5 +59,5 @@ 	setforce v = Annex.changeState $ \s -> s { Annex.force = v } 	setfast v = Annex.changeState $ \s -> s { Annex.fast = v } 	setforcebackend v = Annex.changeState $ \s -> s { Annex.forcebackend = Just v }-	setdebug = Annex.changeGitConfig $ \c -> c { annexDebug = True }-	unsetdebug = Annex.changeGitConfig $ \c -> c { annexDebug = False }+	setdebug = Annex.overrideGitConfig $ \c -> c { annexDebug = True }+	unsetdebug = Annex.overrideGitConfig $ \c -> c { annexDebug = False }
Command/AddUrl.hs view
@@ -20,6 +20,7 @@ import Annex.Content import Annex.Ingest import Annex.CheckIgnore+import Annex.Perms import Annex.UUID import Annex.YoutubeDl import Logs.Web@@ -168,7 +169,7 @@ downloadRemoteFile :: AddUnlockedMatcher -> Remote -> DownloadOptions -> URLString -> FilePath -> Maybe Integer -> Annex (Maybe Key) downloadRemoteFile addunlockedmatcher r o uri file sz = checkCanAdd file $ do 	let urlkey = Backend.URL.fromUrl uri sz-	liftIO $ createDirectoryIfMissing True (parentDir file)+	createWorkTreeDirectory (parentDir file) 	ifM (Annex.getState Annex.fast <||> pure (relaxedOption o)) 		( do 			addWorkTree addunlockedmatcher (Remote.uuid r) loguri file urlkey Nothing@@ -271,7 +272,7 @@ 		) 	normalfinish tmp = checkCanAdd file $ do 		showDestinationFile file-		liftIO $ createDirectoryIfMissing True (parentDir file)+		createWorkTreeDirectory (parentDir file) 		finishDownloadWith addunlockedmatcher tmp webUUID url file 	tryyoutubedl tmp 		-- Ask youtube-dl what filename it will download@@ -357,7 +358,7 @@ 		tmp <- fromRepo $ gitAnnexTmpObjectLocation dummykey 		ok <- Transfer.notifyTransfer Transfer.Download url $ 			Transfer.download u dummykey afile Transfer.stdRetry $ \p -> do-				liftIO $ createDirectoryIfMissing True (parentDir tmp)+				createAnnexDirectory (parentDir tmp) 				downloader tmp p 		if ok 			then return (Just tmp)@@ -389,9 +390,9 @@ 	Nothing -> go 	Just tmp -> do 		-- Move to final location for large file check.-		pruneTmpWorkDirBefore tmp $ \_ -> liftIO $ do-			createDirectoryIfMissing True (takeDirectory file)-			renameFile tmp file+		pruneTmpWorkDirBefore tmp $ \_ -> do+			createWorkTreeDirectory (takeDirectory file)+			liftIO $ renameFile tmp file 		largematcher <- largeFilesMatcher 		large <- checkFileMatcher largematcher file 		if large@@ -438,7 +439,7 @@ nodownloadWeb' :: AddUnlockedMatcher -> URLString -> Key -> FilePath -> Annex (Maybe Key) nodownloadWeb' addunlockedmatcher url key file = checkCanAdd file $ do 	showDestinationFile file-	liftIO $ createDirectoryIfMissing True (parentDir file)+	createWorkTreeDirectory (parentDir file) 	addWorkTree addunlockedmatcher webUUID url file key Nothing 	return (Just key) 
Command/Config.hs view
@@ -1,6 +1,6 @@ {- git-annex command  -- - Copyright 2017 Joey Hess <id@joeyh.name>+ - Copyright 2017-2020 Joey Hess <id@joeyh.name>  -  - Licensed under the GNU AGPL version 3 or higher.  -}@@ -12,6 +12,7 @@ import Command import Logs.Config import Config+import Types.GitConfig (globalConfigs) import Git.Types (ConfigKey(..), fromConfigValue)  import qualified Data.ByteString.Char8 as S8@@ -53,24 +54,29 @@ 		)  seek :: Action -> CommandSeek-seek (SetConfig ck@(ConfigKey name) val) = commandAction $+seek (SetConfig ck@(ConfigKey name) val) = checkIsGlobalConfig ck $ commandAction $ 	startingUsualMessages (decodeBS' name) (ActionItemOther (Just (fromConfigValue val))) $ do 		setGlobalConfig ck val 		when (needLocalUpdate ck) $ 			setConfig ck (fromConfigValue val) 		next $ return True-seek (UnsetConfig ck@(ConfigKey name)) = commandAction $+seek (UnsetConfig ck@(ConfigKey name)) = checkIsGlobalConfig ck $ commandAction $ 	startingUsualMessages (decodeBS' name) (ActionItemOther (Just "unset")) $do 		unsetGlobalConfig ck 		when (needLocalUpdate ck) $ 			unsetConfig ck 		next $ return True-seek (GetConfig ck) = commandAction $+seek (GetConfig ck) = checkIsGlobalConfig ck $ commandAction $ 	startingCustomOutput (ActionItemOther Nothing) $ do 		getGlobalConfig ck >>= \case 			Nothing -> return () 			Just (ConfigValue v) -> liftIO $ S8.putStrLn v 		next $ return True++checkIsGlobalConfig :: ConfigKey -> Annex a -> Annex a+checkIsGlobalConfig ck@(ConfigKey name) a+	| elem ck globalConfigs = a+	| otherwise = giveup $ decodeBS name ++ " is not a configuration setting that can be stored in the git-annex branch"  needLocalUpdate :: ConfigKey -> Bool needLocalUpdate (ConfigKey "annex.securehashesonly") = True
Command/Expire.hs view
@@ -17,6 +17,7 @@ import qualified Remote import Utility.HumanTime +import Control.Monad.Fail as Fail (MonadFail(..)) import Data.Time.Clock.POSIX import qualified Data.Map as M @@ -105,9 +106,9 @@ 		Nothing -> giveup $ "bad expire time: " ++ s 		Just d -> Just (now - durationToPOSIXTime d) -parseActivity :: Monad m => String -> m Activity+parseActivity :: MonadFail m => String -> m Activity parseActivity s = case readish s of-	Nothing -> fail $ "Unknown activity. Choose from: " ++ +	Nothing -> Fail.fail $ "Unknown activity. Choose from: " ++  		unwords (map show [minBound..maxBound :: Activity]) 	Just v -> return v 
Command/Fix.hs view
@@ -67,7 +67,7 @@  breakHardLink :: RawFilePath -> Key -> RawFilePath -> CommandPerform breakHardLink file key obj = do-	replaceFile (fromRawFilePath file) $ \tmp -> do+	replaceWorkTreeFile (fromRawFilePath file) $ \tmp -> do 		mode <- liftIO $ catchMaybeIO $ fileMode <$> R.getFileStatus file 		let obj' = fromRawFilePath obj 		unlessM (checkedCopyFile key obj' tmp mode) $@@ -79,7 +79,7 @@  makeHardLink :: RawFilePath -> Key -> CommandPerform makeHardLink file key = do-	replaceFile (fromRawFilePath file) $ \tmp -> do+	replaceWorkTreeFile (fromRawFilePath file) $ \tmp -> do 		mode <- liftIO $ catchMaybeIO $ fileMode <$> R.getFileStatus file 		linkFromAnnex key tmp mode >>= \case 			LinkAnnexFailed -> error "unable to make hard link"@@ -88,17 +88,16 @@  fixSymlink :: FilePath -> FilePath -> CommandPerform fixSymlink file link = do-	liftIO $ do #if ! defined(mingw32_HOST_OS)-		-- preserve mtime of symlink-		mtime <- catchMaybeIO $ modificationTimeHiRes-			<$> getSymbolicLinkStatus file+	-- preserve mtime of symlink+	mtime <- liftIO $ catchMaybeIO $ modificationTimeHiRes+		<$> getSymbolicLinkStatus file #endif-		createDirectoryIfMissing True (parentDir file)-		removeFile file-		createSymbolicLink link file+	createWorkTreeDirectory (parentDir file)+	liftIO $ removeFile file+	liftIO $ createSymbolicLink link file #if ! defined(mingw32_HOST_OS)-		maybe noop (\t -> touch file t False) mtime+	liftIO $ maybe noop (\t -> touch file t False) mtime #endif 	next $ cleanupSymlink file 
Command/FromKey.hs view
@@ -13,6 +13,7 @@ import qualified Annex.Queue import Annex.Content import Annex.WorkTree+import Annex.Perms import qualified Annex import qualified Backend.URL @@ -85,7 +86,7 @@ 		( hasothercontent 		, do 			link <- calcRepo $ gitAnnexLink file key-			liftIO $ createDirectoryIfMissing True (parentDir file)+			createWorkTreeDirectory (parentDir file) 			liftIO $ createSymbolicLink link file 			Annex.Queue.addCommand "add" [Param "--"] [file] 			next $ return True
Command/Fsck.hs view
@@ -219,7 +219,7 @@ 	go want have 		| want /= fromRawFilePath (fromInternalGitPath have) = do 			showNote "fixing link"-			liftIO $ createDirectoryIfMissing True (parentDir (fromRawFilePath file))+			createWorkTreeDirectory (parentDir (fromRawFilePath file)) 			liftIO $ removeFile (fromRawFilePath file) 			addAnnexLink want file 		| otherwise = noop@@ -332,7 +332,7 @@ 	case mk of 		Just k | k == key -> whenM (inAnnex key) $ do 			showNote "fixing worktree content"-			replaceFile (fromRawFilePath file) $ \tmp -> do+			replaceWorkTreeFile (fromRawFilePath file) $ \tmp -> do 				mode <- liftIO $ catchMaybeIO $ fileMode <$> R.getFileStatus file 				ifM (annexThin <$> Annex.getGitConfig) 					( void $ linkFromAnnex key tmp mode
Command/FuzzTest.hs view
@@ -13,6 +13,7 @@ import qualified Annex import qualified Git.Config import Config+import Annex.Perms import Utility.ThreadScheduler import Utility.DiskFree import Git.Types (fromConfigKey)@@ -172,10 +173,10 @@ 		]  runFuzzAction :: FuzzAction -> Annex ()-runFuzzAction (FuzzAdd (FuzzFile f)) = liftIO $ do-	createDirectoryIfMissing True $ parentDir f-	n <- getStdRandom random :: IO Int-	writeFile f $ show n ++ "\n"+runFuzzAction (FuzzAdd (FuzzFile f)) = do+	createWorkTreeDirectory (parentDir f)+	n <- liftIO (getStdRandom random :: IO Int)+	liftIO $ writeFile f $ show n ++ "\n" runFuzzAction (FuzzDelete (FuzzFile f)) = liftIO $ nukeFile f runFuzzAction (FuzzMove (FuzzFile src) (FuzzFile dest)) = liftIO $ 	rename src dest
Command/Import.hs view
@@ -25,6 +25,7 @@ import Annex.Ingest import Annex.InodeSentinal import Annex.Import+import Annex.Perms import Annex.RemoteTrackingBranch import Utility.InodeCache import Logs.Location@@ -176,12 +177,12 @@ 	importfilechecked ld k = do 		-- Move or copy the src file to the dest file. 		-- The dest file is what will be ingested.-		liftIO $ createDirectoryIfMissing True (parentDir destfile)+		createWorkTreeDirectory (parentDir destfile) 		liftIO $ if mode == Duplicate || mode == SkipDuplicates 			then void $ copyFileExternal CopyAllMetaData srcfile destfile 			else moveFile srcfile destfile 		-- Get the inode cache of the dest file. It should be-		-- weakly the same as the origianlly locked down file's+		-- weakly the same as the originally locked down file's 		-- inode cache. (Since the file may have been copied, 		-- its inodes may not be the same.) 		newcache <- withTSDelta $ liftIO . genInodeCache destfile'
Command/Init.hs view
@@ -13,6 +13,7 @@ import Types.RepoVersion import qualified Annex.SpecialRemote +import Control.Monad.Fail as Fail (MonadFail(..)) import qualified Data.Map as M 	 cmd :: Command@@ -33,14 +34,14 @@ 		<> help "Override default annex.version" 		)) -parseRepoVersion :: Monad m => String -> m RepoVersion+parseRepoVersion :: MonadFail m => String -> m RepoVersion parseRepoVersion s = case RepoVersion <$> readish s of-	Nothing -> fail $ "version parse error"+	Nothing -> Fail.fail $ "version parse error" 	Just v 		| v `elem` supportedVersions -> return v 		| otherwise -> case M.lookup v autoUpgradeableVersions of 			Just v' -> return v'-			Nothing -> fail $ s ++ " is not a currently supported repository version"+			Nothing -> Fail.fail $ s ++ " is not a currently supported repository version"  seek :: InitOptions -> CommandSeek seek = commandAction . start
Command/Lock.hs view
@@ -74,7 +74,7 @@ 		mfc <- withTSDelta (liftIO . genInodeCache file) 		unlessM (sameInodeCache obj (maybeToList mfc)) $ do 			let obj' = fromRawFilePath obj-			modifyContent obj' $ replaceFile obj' $ \tmp -> do+			modifyContent obj' $ replaceGitAnnexDirFile obj' $ \tmp -> do 				unlessM (checkedCopyFile key obj' tmp Nothing) $ 					giveup "unable to lock file" 			Database.Keys.storeInodeCaches key [obj]
Command/ReKey.hs view
@@ -93,7 +93,7 @@ 			st <- liftIO $ R.getFileStatus file 			when (linkCount st > 1) $ do 				freezeContent oldobj-				replaceFile (fromRawFilePath file) $ \tmp -> do+				replaceWorkTreeFile (fromRawFilePath file) $ \tmp -> do 					unlessM (checkedCopyFile oldkey oldobj tmp Nothing) $ 						error "can't lock old key" 					thawContent tmp
Command/Smudge.hs view
@@ -176,7 +176,7 @@ 	checkmatcher d 		| dotfile file = ifM (getGitConfigVal annexDotFiles) 			( go-			, return False+			, d 			) 		| otherwise = go 	  where
Command/Unlock.hs view
@@ -29,9 +29,6 @@ seek :: CmdParams -> CommandSeek seek ps = withFilesInGit (commandAction . whenAnnexed start) =<< workTreeItems ps -{- Before v6, the unlock subcommand replaces the symlink with a copy of- - the file's content. In v6 and above, it converts the file from a symlink- - to a pointer. -} start :: RawFilePath -> Key -> CommandStart start file key = ifM (isJust <$> isAnnexLink file) 	( starting "unlock" (mkActionItem (key, AssociatedFile (Just file))) $@@ -42,7 +39,7 @@ perform :: RawFilePath -> Key -> CommandPerform perform dest key = do 	destmode <- liftIO $ catchMaybeIO $ fileMode <$> R.getFileStatus dest-	replaceFile (fromRawFilePath dest) $ \tmp ->+	replaceWorkTreeFile (fromRawFilePath dest) $ \tmp -> 		ifM (inAnnex key) 			( do 				r <- linkFromAnnex key tmp destmode
Command/Upgrade.hs view
@@ -1,6 +1,6 @@ {- git-annex command  -- - Copyright 2011 Joey Hess <id@joeyh.name>+ - Copyright 2011-2020 Joey Hess <id@joeyh.name>  -  - Licensed under the GNU AGPL version 3 or higher.  -}@@ -20,13 +20,28 @@ 	noDaemonRunning $ 	-- ^ avoid upgrading repo out from under daemon 	command "upgrade" SectionMaintenance "upgrade repository"-		paramNothing (withParams seek)+		paramNothing (seek <$$> optParser) -seek :: CmdParams -> CommandSeek-seek = withNothing (commandAction start)+data UpgradeOptions = UpgradeOptions+	{ autoOnly :: Bool+	} -start :: CommandStart-start = starting "upgrade" (ActionItemOther Nothing) $ do+optParser :: CmdParamsDesc -> Parser UpgradeOptions+optParser _ = UpgradeOptions+	<$> switch+		( long "autoonly"+		<> help "only do automatic upgrades"+		)++seek :: UpgradeOptions -> CommandSeek+seek o = commandAction (start o)++start :: UpgradeOptions -> CommandStart+start (UpgradeOptions { autoOnly = True }) = do+	starting "upgrade" (ActionItemOther Nothing) $ do+	getVersion >>= maybe noop checkUpgrade+	next $ return True+start _ = starting "upgrade" (ActionItemOther Nothing) $ do 	whenM (isNothing <$> getVersion) $ do 		initialize Nothing Nothing 	r <- upgrade False latestVersion
Command/Whereis.hs view
@@ -92,7 +92,18 @@ 		<$> askremote 		<*> claimedurls   where-	askremote = maybe (pure []) (flip id key) (whereisKey remote)+	askremote = case whereisKey remote of+		Nothing -> pure []+		Just w -> tryNonAsync (w key) >>= \case+			Right l -> pure l+			Left e -> do+				warning $ unwords+					[ "unable to query remote"+					, name remote+					, "for urls:"+					, show e+					]+				return [] 	claimedurls = do 		us <- map fst  			. filter (\(_, d) -> d == OtherDownloader)
Config.hs view
@@ -5,10 +5,14 @@  - Licensed under the GNU AGPL version 3 or higher.  -} -{-# LANGUAGE TypeSynonymInstances, FlexibleInstances #-} {-# LANGUAGE OverloadedStrings #-} -module Config where+module Config (+	module Config,+	annexConfig,+	remoteAnnexConfig,+	remoteConfig,+) where  import Annex.Common import qualified Git@@ -18,13 +22,9 @@ import Config.Cost import Config.DynamicConfig import Types.Availability+import Types.GitConfig import Git.Types-import qualified Types.Remote as Remote -import qualified Data.ByteString as S--type UnqualifiedConfigKey = S.ByteString- {- Looks up a setting in git config. This is not as efficient as using the  - GitConfig type. -} getConfig :: ConfigKey -> ConfigValue -> Annex ConfigValue@@ -50,31 +50,6 @@ unsetConfig :: ConfigKey -> Annex () unsetConfig key = void $ inRepo $ Git.Config.unset key -class RemoteNameable r where-	getRemoteName :: r -> RemoteName--instance RemoteNameable Git.Repo where-	getRemoteName r = fromMaybe "" (Git.remoteName r)--instance RemoteNameable RemoteName where-	 getRemoteName = id--instance RemoteNameable Remote where-	getRemoteName = Remote.name--{- A per-remote config setting in git config. -}-remoteConfig :: RemoteNameable r => r -> UnqualifiedConfigKey -> ConfigKey-remoteConfig r key = ConfigKey $-	"remote." <> encodeBS' (getRemoteName r) <> "." <> key--{- A per-remote config annex setting in git config. -}-remoteAnnexConfig :: RemoteNameable r => r -> UnqualifiedConfigKey -> ConfigKey-remoteAnnexConfig r key = remoteConfig r ("annex-" <> key)--{- A global annex setting in git config. -}-annexConfig :: UnqualifiedConfigKey -> ConfigKey-annexConfig key = ConfigKey ("annex." <> key)- {- Calculates cost for a remote. Either the specific default, or as configured   - by remote.<name>.annex-cost, or if remote.<name>.annex-cost-command  - is set and prints a number, that is used. -}@@ -106,11 +81,5 @@ crippledFileSystem = annexCrippledFileSystem <$> Annex.getGitConfig  setCrippledFileSystem :: Bool -> Annex ()-setCrippledFileSystem b = do+setCrippledFileSystem b = 	setConfig (annexConfig "crippledfilesystem") (Git.Config.boolConfig b)-	Annex.changeGitConfig $ \c -> c { annexCrippledFileSystem = b }--yesNo :: String -> Maybe Bool-yesNo "yes" = Just True-yesNo "no" = Just False-yesNo _ = Nothing
Config/GitConfig.hs view
@@ -17,7 +17,8 @@  - repository-global defaults when the GitConfig does not yet   - have a value.  -- - Note: Be sure to add the config value to mergeGitConfig.+ - Note: Be sure to add the config to mergeGitConfig and to+ - globalConfigs.  -} getGitConfigVal :: (GitConfig -> Configurable a) -> Annex a getGitConfigVal f = getGitConfigVal' f >>= \case@@ -35,6 +36,6 @@ 		-- config makes all repository-global default 		-- values populate the GitConfig with HasGlobalConfig 		-- values, so it will only need to be done once.-		Annex.changeGitConfig (\gc -> mergeGitConfig gc globalgc)+		Annex.overrideGitConfig (\gc -> mergeGitConfig gc globalgc) 		f <$> Annex.getGitConfig 	c -> return c
Config/Smudge.hs view
@@ -33,8 +33,9 @@ 	gf <- Annex.fromRepo Git.attributes 	lfs <- readattr lf 	gfs <- readattr gf+	gittop <- fromRawFilePath . Git.localGitDir <$> gitRepo 	liftIO $ unless ("filter=annex" `isInfixOf` (lfs ++ gfs)) $ do-		createDirectoryIfMissing True (takeDirectory lf)+		createDirectoryUnder gittop (takeDirectory lf) 		writeFile lf (lfs ++ "\n" ++ unlines stdattr)   where 	readattr = liftIO . catchDefaultIO "" . readFileStrict
Database/Init.hs view
@@ -1,6 +1,6 @@ {- Persistent sqlite database initialization  -- - Copyright 2015-2018 Joey Hess <id@joeyh.name>+ - Copyright 2015-2020 Joey Hess <id@joeyh.name>  -  - Licensed under the GNU AGPL version 3 or higher.  -}@@ -29,9 +29,10 @@ 	let dbdir = takeDirectory db 	let tmpdbdir = dbdir ++ ".tmp" 	let tmpdb = tmpdbdir </> "db"-	let tdb = T.pack tmpdb	+	let tdb = T.pack tmpdb+	top <- parentDir . fromRawFilePath <$> fromRepo gitAnnexDir 	liftIO $ do-		createDirectoryIfMissing True tmpdbdir+		createDirectoryUnder top tmpdbdir 		runSqliteInfo (enableWAL tdb) migration 	setAnnexDirPerm tmpdbdir 	-- Work around sqlite bug that prevents it from honoring
Git/LsFiles.hs view
@@ -40,12 +40,36 @@ import qualified Data.Map as M import qualified Data.ByteString.Lazy as L -{- Scans for files that are checked into git's index at the specified locations. -}+{- It's only safe to use git ls-files on the current repo, not on a remote.+ -+ - Git has some strange behavior when git ls-files is used with repos+ - that are not the one that the cwd is in:+ - git --git-dir=../foo/.git --worktree=../foo ../foo fails saying + - "../foo is outside repository".+ - That does not happen when an absolute path is provided.+ -+ - Also, the files output by ls-files are relative to the cwd. + - Unless it's run on remote. Then it's relative to the top of the remote+ - repo.+ -+ - So, best to avoid that class of problems.+ -}+safeForLsFiles :: Repo -> Bool+safeForLsFiles r = isNothing (remoteName r)++guardSafeForLsFiles :: Repo -> IO a -> IO a+guardSafeForLsFiles r a+	| safeForLsFiles r = a+	| otherwise = error $ "git ls-files is unsafe to run on repository " ++ repoDescribe r++{- Lists files that are checked into git's index at the specified paths.+ - With no paths, all files are listed.+ -} inRepo :: [RawFilePath] -> Repo -> IO ([RawFilePath], IO Bool) inRepo = inRepo' []   inRepo' :: [CommandParam] -> [RawFilePath] -> Repo -> IO ([RawFilePath], IO Bool)-inRepo' ps l repo = pipeNullSplit' params repo+inRepo' ps l repo = guardSafeForLsFiles repo $ pipeNullSplit' params repo   where 	params =  		Param "ls-files" :@@ -64,7 +88,8 @@ notInRepo = notInRepo' []  notInRepo' :: [CommandParam] -> Bool -> [RawFilePath] -> Repo -> IO ([RawFilePath], IO Bool)-notInRepo' ps include_ignored l repo = pipeNullSplit' params repo+notInRepo' ps include_ignored l repo = guardSafeForLsFiles repo $+	pipeNullSplit' params repo   where 	params = concat 		[ [ Param "ls-files", Param "--others"]@@ -85,18 +110,20 @@ {- Finds all files in the specified locations, whether checked into git or  - not. -} allFiles :: [RawFilePath] -> Repo -> IO ([RawFilePath], IO Bool)-allFiles l = pipeNullSplit' $-	Param "ls-files" :-	Param "--cached" :-	Param "--others" :-	Param "-z" :-	Param "--" :-	map (File . fromRawFilePath) l+allFiles l repo = guardSafeForLsFiles repo $ pipeNullSplit' params repo+  where+	params =+		Param "ls-files" :+		Param "--cached" :+		Param "--others" :+		Param "-z" :+		Param "--" :+		map (File . fromRawFilePath) l  {- Returns a list of files in the specified locations that have been  - deleted. -} deleted :: [RawFilePath] -> Repo -> IO ([RawFilePath], IO Bool)-deleted l repo = pipeNullSplit' params repo+deleted l repo = guardSafeForLsFiles repo $ pipeNullSplit' params repo   where 	params = 		Param "ls-files" :@@ -108,7 +135,7 @@ {- Returns a list of files in the specified locations that have been  - modified. -} modified :: [RawFilePath] -> Repo -> IO ([RawFilePath], IO Bool)-modified l repo = pipeNullSplit' params repo+modified l repo = guardSafeForLsFiles repo $ pipeNullSplit' params repo   where 	params =  		Param "ls-files" :@@ -120,7 +147,7 @@ {- Files that have been modified or are not checked into git (and are not  - ignored). -} modifiedOthers :: [RawFilePath] -> Repo -> IO ([RawFilePath], IO Bool)-modifiedOthers l repo = pipeNullSplit' params repo+modifiedOthers l repo = guardSafeForLsFiles repo $ pipeNullSplit' params repo   where 	params =  		Param "ls-files" :@@ -141,7 +168,8 @@ stagedNotDeleted = staged' [Param "--diff-filter=ACMRT"]  staged' :: [CommandParam] -> [RawFilePath] -> Repo -> IO ([RawFilePath], IO Bool)-staged' ps l repo = pipeNullSplit' (prefix ++ ps ++ suffix) repo+staged' ps l repo = guardSafeForLsFiles repo $+	pipeNullSplit' (prefix ++ ps ++ suffix) repo   where 	prefix = [Param "diff", Param "--cached", Param "--name-only", Param "-z"] 	suffix = Param "--" : map (File . fromRawFilePath) l@@ -160,7 +188,7 @@ {- Gets details about staged files, including the Sha of their staged  - contents. -} stagedDetails' :: [CommandParam] -> [RawFilePath] -> Repo -> IO ([StagedDetails], IO Bool)-stagedDetails' ps l repo = do+stagedDetails' ps l repo = guardSafeForLsFiles repo $ do 	(ls, cleanup) <- pipeNullSplit params repo 	return (map parseStagedDetails ls, cleanup)   where@@ -188,7 +216,7 @@ typeChanged = typeChanged' []  typeChanged' :: [CommandParam] -> [RawFilePath] -> Repo -> IO ([RawFilePath], IO Bool)-typeChanged' ps l repo = do+typeChanged' ps l repo = guardSafeForLsFiles repo $ do 	(fs, cleanup) <- pipeNullSplit (prefix ++ ps ++ suffix) repo 	-- git diff returns filenames relative to the top of the git repo; 	-- convert to filenames relative to the cwd, like git ls-files.@@ -228,7 +256,7 @@  - If a line is omitted, that side removed the file.  -} unmerged :: [RawFilePath] -> Repo -> IO ([Unmerged], IO Bool)-unmerged l repo = do+unmerged l repo = guardSafeForLsFiles repo $ do 	(fs, cleanup) <- pipeNullSplit params repo 	return (reduceUnmerged [] $ catMaybes $ map (parseUnmerged . decodeBL') fs, cleanup)   where@@ -292,7 +320,7 @@  - point in the future. If the output is not as expected, will use Nothing.  -} inodeCaches :: [RawFilePath] -> Repo -> IO ([(FilePath, Maybe InodeCache)], IO Bool)-inodeCaches locs repo = do+inodeCaches locs repo = guardSafeForLsFiles repo $ do 	(ls, cleanup) <- pipeNullSplit params repo 	return (parse Nothing (map decodeBL ls), cleanup)   where
Git/Repair.hs view
@@ -245,8 +245,9 @@ 		nukeFile f   where 	makeref (sha, ref) = do-		let dest = fromRawFilePath (localGitDir r) </> fromRef ref-		createDirectoryIfMissing True (parentDir dest)+		let gitd = fromRawFilePath (localGitDir r)+		let dest = gitd </> fromRef ref+		createDirectoryUnder gitd (parentDir dest) 		unlessM (doesFileExist dest) $ 			writeFile dest (fromRef sha) 
Logs/File.hs view
@@ -29,7 +29,7 @@ withLogHandle :: FilePath -> (Handle -> Annex a) -> Annex a withLogHandle f a = do 	createAnnexDirectory (parentDir f)-	replaceFile f $ \tmp ->+	replaceGitAnnexDirFile f $ \tmp -> 		bracket (setup tmp) cleanup a   where 	setup tmp = do
Remote/Directory.hs view
@@ -170,13 +170,13 @@  store :: FilePath -> ChunkConfig -> Key -> L.ByteString -> MeterUpdate -> Annex Bool store d chunkconfig k b p = liftIO $ do-	void $ tryIO $ createDirectoryIfMissing True tmpdir+	void $ tryIO $ createDirectoryUnder d tmpdir 	case chunkconfig of-		LegacyChunks chunksize -> Legacy.store chunksize finalizeStoreGeneric k b p tmpdir destdir+		LegacyChunks chunksize -> Legacy.store d chunksize (finalizeStoreGeneric d) k b p tmpdir destdir 		_ -> do 			let tmpf = tmpdir </> kf 			meteredWriteFile p tmpf b-			finalizeStoreGeneric tmpdir destdir+			finalizeStoreGeneric d tmpdir destdir 			return True   where 	tmpdir = addTrailingPathSeparator $ d </> "tmp" </> kf@@ -187,11 +187,11 @@  - in the dest directory, moves it into place. Anything already existing  - in the dest directory will be deleted. File permissions will be locked  - down. -}-finalizeStoreGeneric :: FilePath -> FilePath -> IO ()-finalizeStoreGeneric tmp dest = do+finalizeStoreGeneric :: FilePath -> FilePath -> FilePath -> IO ()+finalizeStoreGeneric d tmp dest = do 	void $ tryIO $ allowWrite dest -- may already exist 	void $ tryIO $ removeDirectoryRecursive dest -- or not exist-	createDirectoryIfMissing True (parentDir dest)+	createDirectoryUnder d (parentDir dest) 	renameDirectory tmp dest 	-- may fail on some filesystems 	void $ tryIO $ do@@ -267,7 +267,7 @@  storeExportM :: FilePath -> FilePath -> Key -> ExportLocation -> MeterUpdate -> Annex Bool storeExportM d src _k loc p = liftIO $ catchBoolIO $ do-	createDirectoryIfMissing True (takeDirectory dest)+	createDirectoryUnder d (takeDirectory dest) 	-- Write via temp file so that checkPresentGeneric will not 	-- see it until it's fully stored. 	viaTmp (\tmp () -> withMeteredFile src p (L.writeFile tmp)) dest ()@@ -298,7 +298,7 @@ renameExportM d _k oldloc newloc = liftIO $ Just <$> go   where 	go = catchBoolIO $ do-		createDirectoryIfMissing True (takeDirectory dest)+		createDirectoryUnder d (takeDirectory dest) 		renameFile src dest 		removeExportLocation d oldloc 		return True@@ -413,7 +413,7 @@ 	catchIO go (return . Left . show)   where 	go = do-		liftIO $ createDirectoryIfMissing True destdir+		liftIO $ createDirectoryUnder dir destdir 		withTmpFileIn destdir template $ \tmpf tmph -> do 			liftIO $ withMeteredFile src p (L.hPut tmph) 			liftIO $ hFlush tmph
Remote/Directory/LegacyChunked.hs view
@@ -70,9 +70,9 @@ 				feed bytes' (sz - s) ls h 			else return (l:ls) -storeHelper :: (FilePath -> FilePath -> IO ()) -> Key -> ([FilePath] -> IO [FilePath]) -> FilePath -> FilePath -> IO Bool-storeHelper finalizer key storer tmpdir destdir = do-	void $ liftIO $ tryIO $ createDirectoryIfMissing True tmpdir+storeHelper :: FilePath -> (FilePath -> FilePath -> IO ()) -> Key -> ([FilePath] -> IO [FilePath]) -> FilePath -> FilePath -> IO Bool+storeHelper repotop finalizer key storer tmpdir destdir = do+	void $ liftIO $ tryIO $ createDirectoryUnder repotop tmpdir 	Legacy.storeChunks key tmpdir destdir storer recorder finalizer   where 	recorder f s = do@@ -80,8 +80,8 @@ 		writeFile f s 		void $ tryIO $ preventWrite f -store :: ChunkSize -> (FilePath -> FilePath -> IO ()) -> Key -> L.ByteString -> MeterUpdate -> FilePath -> FilePath -> IO Bool-store chunksize finalizer k b p = storeHelper finalizer k $ \dests ->+store :: FilePath -> ChunkSize -> (FilePath -> FilePath -> IO ()) -> Key -> L.ByteString -> MeterUpdate -> FilePath -> FilePath -> IO Bool+store repotop chunksize finalizer k b p = storeHelper repotop finalizer k $ \dests -> 	storeLegacyChunked p chunksize dests b  {- Need to get a single ByteString containing every chunk.
Remote/External.hs view
@@ -183,7 +183,8 @@ 				=<< strictRemoteConfigParser external 			handleRequest external INITREMOTE Nothing $ \resp -> case resp of 				INITREMOTE_SUCCESS -> result ()-				INITREMOTE_FAILURE errmsg -> Just $ giveup errmsg+				INITREMOTE_FAILURE errmsg -> Just $ giveup $+					respErrorMessage "INITREMOTE" errmsg 				_ -> Nothing 			-- Any config changes the external made before 			-- responding to INITREMOTE need to be applied to@@ -218,7 +219,7 @@ 			TRANSFER_SUCCESS Upload k' | k == k' -> result True 			TRANSFER_FAILURE Upload k' errmsg | k == k' -> 				Just $ do-					warning errmsg+					warning $ respErrorMessage "TRANSFER" errmsg 					return (Result False) 			_ -> Nothing @@ -229,7 +230,8 @@ 			TRANSFER_SUCCESS Download k' 				| k == k' -> result () 			TRANSFER_FAILURE Download k' errmsg-				| k == k' -> Just $ giveup errmsg+				| k == k' -> Just $ giveup $+					respErrorMessage "TRANSFER" errmsg 			_ -> Nothing  removeKeyM :: External -> Remover@@ -240,7 +242,7 @@ 				| k == k' -> result True 			REMOVE_FAILURE k' errmsg 				| k == k' -> Just $ do-					warning errmsg+					warning $ respErrorMessage "REMOVE" errmsg 					return (Result False) 			_ -> Nothing @@ -254,7 +256,8 @@ 			CHECKPRESENT_FAILURE k' 				| k' == k -> result $ Right False 			CHECKPRESENT_UNKNOWN k' errmsg-				| k' == k -> result $ Left errmsg+				| k' == k -> result $ Left $+					respErrorMessage "CHECKPRESENT" errmsg 			_ -> Nothing  whereisKeyM :: External -> Key -> Annex [String]@@ -270,7 +273,7 @@ 		TRANSFER_SUCCESS Upload k' | k == k' -> result True 		TRANSFER_FAILURE Upload k' errmsg | k == k' -> 			Just $ do-				warning errmsg+				warning $ respErrorMessage "TRANSFER" errmsg 				return (Result False) 		UNSUPPORTED_REQUEST -> Just $ do 			warning "TRANSFEREXPORT not implemented by external special remote"@@ -286,7 +289,7 @@ 			| k == k' -> result True 		TRANSFER_FAILURE Download k' errmsg 			| k == k' -> Just $ do-				warning errmsg+				warning $ respErrorMessage "TRANSFER" errmsg 				return (Result False) 		UNSUPPORTED_REQUEST -> Just $ do 			warning "TRANSFEREXPORT not implemented by external special remote"@@ -304,7 +307,8 @@ 		CHECKPRESENT_FAILURE k' 			| k' == k -> result $ Right False 		CHECKPRESENT_UNKNOWN k' errmsg-			| k' == k -> result $ Left errmsg+			| k' == k -> result $ Left $+				respErrorMessage "CHECKPRESENT" errmsg 		UNSUPPORTED_REQUEST -> result $ 			Left "CHECKPRESENTEXPORT not implemented by external special remote" 		_ -> Nothing@@ -316,7 +320,7 @@ 			| k == k' -> result True 		REMOVE_FAILURE k' errmsg 			| k == k' -> Just $ do-				warning errmsg+				warning $ respErrorMessage "REMOVE" errmsg 				return (Result False) 		UNSUPPORTED_REQUEST -> Just $ do 			warning "REMOVEEXPORT not implemented by external special remote"@@ -420,9 +424,9 @@ 			modifyTVar' (externalConfigChanges st) $ \f -> 				f . M.insert (Accepted setting) (Accepted value) 	handleRemoteRequest (GETCONFIG setting) = do-		value <- fromMaybe ""+		value <- maybe "" fromProposedAccepted 			. (M.lookup (Accepted setting))-			. getRemoteConfigPassedThrough+			. unparsedRemoteConfig 			<$> liftIO (atomically $ readTVar $ externalConfig st) 		send $ VALUE value 	handleRemoteRequest (SETCREDS setting login password) = case (externalUUID external, externalGitConfig external) of@@ -684,13 +688,19 @@ 						setprepared Prepared 						return (Result ()) 					PREPARE_FAILURE errmsg -> Just $ do-						setprepared $ FailedPrepare errmsg-						giveup errmsg+						let errmsg' = respErrorMessage "PREPARE" errmsg+						setprepared $ FailedPrepare errmsg'+						giveup errmsg' 					_ -> Nothing   where 	setprepared status = liftIO $ atomically $ void $ 		swapTVar (externalPrepared st) status +respErrorMessage :: String -> String -> String+respErrorMessage req err+	| null err = req ++ " failed with no reason given"+	| otherwise = err+ {- Caches the cost in the git config to avoid needing to start up an  - external special remote every time time just to ask it what its  - cost is. -}@@ -743,7 +753,8 @@ 		CHECKURL_CONTENTS sz f -> result $ UrlContents sz $ 			if null f then Nothing else Just $ mkSafeFilePath f 		CHECKURL_MULTI l -> result $ UrlMulti $ map mkmulti l-		CHECKURL_FAILURE errmsg -> Just $ giveup errmsg+		CHECKURL_FAILURE errmsg -> Just $ giveup $+			respErrorMessage "CHECKURL" errmsg 		UNSUPPORTED_REQUEST -> giveup "CHECKURL not implemented by external special remote" 		_ -> Nothing   where
Remote/GCrypt.hs view
@@ -49,6 +49,7 @@ import Utility.Metered import Annex.UUID import Annex.Ssh+import Annex.Perms import qualified Remote.Rsync import qualified Remote.Directory import Utility.Rsync@@ -283,7 +284,7 @@ 	 - which is needed for direct rsync of objects to work. 	 -} 	rsyncsetup = Remote.Rsync.withRsyncScratchDir $ \tmp -> do-		liftIO $ createDirectoryIfMissing True $ tmp </> objectDir+		createAnnexDirectory (tmp </> objectDir) 		dummycfg <- liftIO dummyRemoteGitConfig 		(rsynctransport, rsyncurl, _) <- rsyncTransport r dummycfg 		let tmpconfig = tmp </> "config"@@ -368,11 +369,11 @@ 	| not $ Git.repoIsUrl repo =  		byteStorer $ \k b p -> guardUsable repo (return False) $ liftIO $ do 			let tmpdir = Git.repoLocation repo </> "tmp" </> fromRawFilePath (keyFile k)-			void $ tryIO $ createDirectoryIfMissing True tmpdir+			void $ tryIO $ createDirectoryUnder (Git.repoLocation repo) tmpdir 			let tmpf = tmpdir </> fromRawFilePath (keyFile k) 			meteredWriteFile p tmpf b 			let destdir = parentDir $ gCryptLocation repo k-			Remote.Directory.finalizeStoreGeneric tmpdir destdir+			Remote.Directory.finalizeStoreGeneric (Git.repoLocation repo) tmpdir destdir 			return True 	| Git.repoIsSsh repo = if accessShell r 		then fileStorer $ \k f p -> do
Remote/GitLFS.hs view
@@ -167,7 +167,7 @@ 	-- (so it's also usable by git as a non-special remote), 	-- and set remote.name.annex-git-lfs = true 	gitConfigSpecialRemote u c' [("git-lfs", "true")]-	setConfig (remoteConfig (getRemoteName c) "url") url+	setConfig (remoteConfig c "url") url 	return (c', u)   where 	url = maybe (giveup "Specify url=") fromProposedAccepted 
Remote/Helper/Hooks.hs view
@@ -48,7 +48,7 @@ 	dir <- fromRepo gitAnnexRemotesDir 	let lck = dir </> remoteid ++ ".lck" 	whenM (notElem lck . M.keys <$> getLockCache) $ do-		liftIO $ createDirectoryIfMissing True dir+		createAnnexDirectory dir 		firstrun lck 	a   where
Remote/Rsync.hs view
@@ -27,6 +27,7 @@ import Annex.Content import Annex.UUID import Annex.Ssh+import Annex.Perms import Remote.Helper.Special import Remote.Helper.Messages import Remote.Helper.ExportImport@@ -218,7 +219,7 @@ storeGeneric :: RsyncOpts -> MeterUpdate -> FilePath -> (FilePath -> Annex Bool) -> Annex Bool storeGeneric o meterupdate basedest populatedest = withRsyncScratchDir $ \tmp -> do 	let dest = tmp </> basedest-	liftIO $ createDirectoryIfMissing True $ parentDir dest+	createAnnexDirectory (parentDir dest) 	ok <- populatedest dest 	ps <- sendParams 	if ok
Test.hs view
@@ -161,7 +161,7 @@ 		| otherwise = Nothing  properties :: TestTree-properties = localOption (QuickCheckTests 1000) $ testGroup "QuickCheck"+properties = localOption (QuickCheckTests 1000) $ testGroup "QuickCheck" $ 	[ testProperty "prop_encode_decode_roundtrip" Git.Filename.prop_encode_decode_roundtrip 	, testProperty "prop_encode_c_decode_c_roundtrip" Utility.Format.prop_encode_c_decode_c_roundtrip 	, testProperty "prop_isomorphic_key_encode" Key.prop_isomorphic_key_encode@@ -185,8 +185,6 @@ 	, testProperty "prop_parse_build_contentidentifier_log" Logs.ContentIdentifier.prop_parse_build_contentidentifier_log 	, testProperty "prop_read_show_TrustLevel" Types.TrustLevel.prop_read_show_TrustLevel 	, testProperty "prop_parse_build_TrustLevelLog" Logs.Trust.prop_parse_build_TrustLevelLog-	, testProperty "prop_hashes_stable" Utility.Hash.prop_hashes_stable-	, testProperty "prop_mac_stable" Utility.Hash.prop_mac_stable 	, testProperty "prop_schedule_roundtrips" Utility.Scheduled.QuickCheck.prop_schedule_roundtrips 	, testProperty "prop_past_sane" Utility.Scheduled.prop_past_sane 	, testProperty "prop_duration_roundtrips" Utility.HumanTime.prop_duration_roundtrips@@ -198,7 +196,12 @@ 	, testProperty "prop_viewedFile_rountrips" Annex.View.ViewedFile.prop_viewedFile_roundtrips 	, testProperty "prop_b64_roundtrips" Utility.Base64.prop_b64_roundtrips 	, testProperty "prop_standardGroups_parse" Logs.PreferredContent.prop_standardGroups_parse-	]+	] ++ map (uncurry testProperty) combos+  where+	combos = concat+		[ Utility.Hash.props_hashes_stable+		, Utility.Hash.props_macs_stable+		]  {- These tests set up the test environment, but also test some basic parts  - of git-annex. They are always run before the unitTests. -}
Types/GitConfig.hs view
@@ -1,10 +1,11 @@ {- git-annex configuration  -- - Copyright 2012-2019 Joey Hess <id@joeyh.name>+ - Copyright 2012-2020 Joey Hess <id@joeyh.name>  -  - Licensed under the GNU AGPL version 3 or higher.  -} +{-# LANGUAGE TypeSynonymInstances, FlexibleInstances #-} {-# LANGUAGE OverloadedStrings #-}  module Types.GitConfig ( @@ -13,9 +14,14 @@ 	GitConfig(..), 	extractGitConfig, 	mergeGitConfig,+	globalConfigs, 	RemoteGitConfig(..), 	extractRemoteGitConfig, 	dummyRemoteGitConfig,+	annexConfig,+	RemoteNameable(..),+	remoteAnnexConfig,+	remoteConfig, ) where  import Common@@ -43,6 +49,7 @@  import Control.Concurrent.STM import qualified Data.Set as S+import qualified Data.ByteString as B  -- | A configurable value, that may not be fully determined yet because -- the global git config has not yet been loaded.@@ -125,84 +132,86 @@  extractGitConfig :: ConfigSource -> Git.Repo -> GitConfig extractGitConfig configsource r = GitConfig-	{ annexVersion = RepoVersion <$> getmayberead (annex "version")-	, annexUUID = maybe NoUUID toUUID $ getmaybe (annex "uuid")-	, annexNumCopies = NumCopies <$> getmayberead (annex "numcopies")+	{ annexVersion = RepoVersion <$> getmayberead (annexConfig "version")+	, annexUUID = maybe NoUUID toUUID $ getmaybe (annexConfig "uuid")+	, annexNumCopies = NumCopies <$> getmayberead (annexConfig "numcopies") 	, annexDiskReserve = fromMaybe onemegabyte $-		readSize dataUnits =<< getmaybe (annex "diskreserve")-	, annexDirect = getbool (annex "direct") False+		readSize dataUnits =<< getmaybe (annexConfig "diskreserve")+	, annexDirect = getbool (annexConfig "direct") False 	, annexBackend = maybe 		-- annex.backends is the old name of the option, still used 		-- when annex.backend is not set.-		(headMaybe $ getwords (annex "backends"))+		(headMaybe $ getwords (annexConfig "backends")) 		Just-		(getmaybe (annex "backend"))-	, annexQueueSize = getmayberead (annex "queuesize")-	, annexBloomCapacity = getmayberead (annex "bloomcapacity")-	, annexBloomAccuracy = getmayberead (annex "bloomaccuracy")-	, annexSshCaching = getmaybebool (annex "sshcaching")-	, annexAlwaysCommit = getbool (annex "alwayscommit") True-	, annexCommitMessage = getmaybe (annex "commitmessage")-	, annexMergeAnnexBranches = getbool (annex "merge-annex-branches") True-	, annexDelayAdd = getmayberead (annex "delayadd")-	, annexHttpHeaders = getlist (annex "http-headers")-	, annexHttpHeadersCommand = getmaybe (annex "http-headers-command")+		(getmaybe (annexConfig "backend"))+	, annexQueueSize = getmayberead (annexConfig "queuesize")+	, annexBloomCapacity = getmayberead (annexConfig "bloomcapacity")+	, annexBloomAccuracy = getmayberead (annexConfig "bloomaccuracy")+	, annexSshCaching = getmaybebool (annexConfig "sshcaching")+	, annexAlwaysCommit = getbool (annexConfig "alwayscommit") True+	, annexCommitMessage = getmaybe (annexConfig "commitmessage")+	, annexMergeAnnexBranches = getbool (annexConfig "merge-annex-branches") True+	, annexDelayAdd = getmayberead (annexConfig "delayadd")+	, annexHttpHeaders = getlist (annexConfig "http-headers")+	, annexHttpHeadersCommand = getmaybe (annexConfig "http-headers-command") 	, annexAutoCommit = configurable True $ -		getmaybebool (annex "autocommit")+		getmaybebool (annexConfig "autocommit") 	, annexResolveMerge = configurable True $ -		getmaybebool (annex "resolvemerge")+		getmaybebool (annexConfig "resolvemerge") 	, annexSyncContent = configurable False $ -		getmaybebool (annex "synccontent")+		getmaybebool (annexConfig "synccontent") 	, annexSyncOnlyAnnex = configurable False $ -		getmaybebool (annex "synconlyannex")-	, annexDebug = getbool (annex "debug") False-	, annexWebOptions = getwords (annex "web-options")-	, annexYoutubeDlOptions = getwords (annex "youtube-dl-options")-	, annexAriaTorrentOptions = getwords (annex "aria-torrent-options")-	, annexCrippledFileSystem = getbool (annex "crippledfilesystem") False+		getmaybebool (annexConfig "synconlyannex")+	, annexDebug = getbool (annexConfig "debug") False+	, annexWebOptions = getwords (annexConfig "web-options")+	, annexYoutubeDlOptions = getwords (annexConfig "youtube-dl-options")+	, annexAriaTorrentOptions = getwords (annexConfig "aria-torrent-options")+	, annexCrippledFileSystem = getbool (annexConfig "crippledfilesystem") False 	, annexLargeFiles = configurable Nothing $-		fmap Just $ getmaybe (annex "largefiles")-	, annexDotFiles = configurable False $ getmaybebool (annex "dotfiles")-	, annexGitAddToAnnex = getbool (annex "gitaddtoannex") True-	, annexAddSmallFiles = getbool (annex "addsmallfiles") True-	, annexFsckNudge = getbool (annex "fscknudge") True-	, annexAutoUpgrade = toAutoUpgrade $ getmaybe (annex "autoupgrade")+		fmap Just $ getmaybe (annexConfig "largefiles")+	, annexDotFiles = configurable False $+		getmaybebool (annexConfig "dotfiles")+	, annexGitAddToAnnex = getbool (annexConfig "gitaddtoannex") True+	, annexAddSmallFiles = getbool (annexConfig "addsmallfiles") True+	, annexFsckNudge = getbool (annexConfig "fscknudge") True+	, annexAutoUpgrade = toAutoUpgrade $+		getmaybe (annexConfig "autoupgrade") 	, annexExpireUnused = maybe Nothing Just . parseDuration-		<$> getmaybe (annex "expireunused")-	, annexSecureEraseCommand = getmaybe (annex "secure-erase-command")-	, annexGenMetaData = getbool (annex "genmetadata") False-	, annexListen = getmaybe (annex "listen")-	, annexStartupScan = getbool (annex "startupscan") True-	, annexHardLink = getbool (annex "hardlink") False-	, annexThin = getbool (annex "thin") False+		<$> getmaybe (annexConfig "expireunused")+	, annexSecureEraseCommand = getmaybe (annexConfig "secure-erase-command")+	, annexGenMetaData = getbool (annexConfig "genmetadata") False+	, annexListen = getmaybe (annexConfig "listen")+	, annexStartupScan = getbool (annexConfig "startupscan") True+	, annexHardLink = getbool (annexConfig "hardlink") False+	, annexThin = getbool (annexConfig "thin") False 	, annexDifferences = getDifferences r 	, annexUsedRefSpec = either (const Nothing) Just . parseRefSpec -		=<< getmaybe (annex "used-refspec")-	, annexVerify = getbool (annex "verify") True-	, annexPidLock = getbool (annex "pidlock") False+		=<< getmaybe (annexConfig "used-refspec")+	, annexVerify = getbool (annexConfig "verify") True+	, annexPidLock = getbool (annexConfig "pidlock") False 	, annexPidLockTimeout = Seconds $ fromMaybe 300 $-		getmayberead (annex "pidlocktimeout")+		getmayberead (annexConfig "pidlocktimeout") 	, annexAddUnlocked = configurable Nothing $-		fmap Just $ getmaybe (annex "addunlocked")-	, annexSecureHashesOnly = getbool (annex "securehashesonly") False-	, annexRetry = getmayberead (annex "retry")+		fmap Just $ getmaybe (annexConfig "addunlocked")+	, annexSecureHashesOnly = getbool (annexConfig "securehashesonly") False+	, annexRetry = getmayberead (annexConfig "retry") 	, annexRetryDelay = Seconds-		<$> getmayberead (annex "retrydelay")+		<$> getmayberead (annexConfig "retrydelay") 	, annexAllowedUrlSchemes = S.fromList $ map mkScheme $ 		maybe ["http", "https", "ftp"] words $-			getmaybe (annex "security.allowed-url-schemes")+			getmaybe (annexConfig "security.allowed-url-schemes") 	, annexAllowedIPAddresses = fromMaybe "" $-		getmaybe (annex "security.allowed-ip-addresses")+		getmaybe (annexConfig "security.allowed-ip-addresses") 			<|>-		getmaybe (annex "security.allowed-http-addresses") -- old name+		getmaybe (annexConfig "security.allowed-http-addresses") -- old name 	, annexAllowUnverifiedDownloads = (== Just "ACKTHPPT") $-		getmaybe (annex "security.allow-unverified-downloads")-	, annexMaxExtensionLength = getmayberead (annex "maxextensionlength")+		getmaybe (annexConfig "security.allow-unverified-downloads")+	, annexMaxExtensionLength = getmayberead (annexConfig "maxextensionlength") 	, annexJobs = fromMaybe NonConcurrent $ -		parseConcurrency =<< getmaybe (annex "jobs")-	, annexCacheCreds = getbool (annex "cachecreds") True-	, annexAutoUpgradeRepository = getbool (annex "autoupgraderepository") True-	, annexCommitMode = if getbool (annex "allowsign") False+		parseConcurrency =<< getmaybe (annexConfig "jobs")+	, annexCacheCreds = getbool (annexConfig "cachecreds") True+	, annexAutoUpgradeRepository = getbool (annexConfig "autoupgraderepository") True+	, annexCommitMode = if getbool (annexConfig "allowsign") False 		then ManualCommit 		else AutomaticCommit 	, coreSymlinks = getbool "core.symlinks" True@@ -225,8 +234,6 @@ 		FromGitConfig -> HasGitConfig v 		FromGlobalConfig -> HasGlobalConfig v -	annex k = ConfigKey $ "annex." <> k-			 	onemegabyte = 1000000  {- Merge a GitConfig that comes from git-config with one containing@@ -249,6 +256,18 @@ 			_ -> HasGitConfig d 		HasGlobalConfig v -> HasGlobalConfig v +{- Configs that can be set repository-global. -}+globalConfigs :: [ConfigKey]+globalConfigs =+	[ annexConfig "autocommit"+	, annexConfig "synccontent"+	, annexConfig "synconlyannex"+	, annexConfig "resolvemerge"+	, annexConfig "largefiles"+	, annexConfig "dotfiles"+	, annexConfig "addunlocked"+	]+ {- Per-remote git-annex settings. Each setting corresponds to a git-config  - key such as <remote>.annex-foo, or if that is not set, a default from  - annex.foo.@@ -366,14 +385,10 @@ 	getmaybebool k = Git.Config.isTrueFalse' =<< getmaybe' k 	getmayberead k = readish =<< getmaybe k 	getmaybe = fmap fromConfigValue . getmaybe'-	getmaybe' k = mplus (Git.Config.getMaybe (key k) r)-		(Git.Config.getMaybe (remotekey k) r)+	getmaybe' k = mplus (Git.Config.getMaybe (annexConfig k) r)+		(Git.Config.getMaybe (remoteAnnexConfig remotename k) r) 	getoptions k = fromMaybe [] $ words <$> getmaybe k -	key k = ConfigKey $ "annex." <> k-	remotekey k = ConfigKey $-		"remote." <> encodeBS' remotename <> ".annex-" <> k- notempty :: Maybe String -> Maybe String	 notempty Nothing = Nothing notempty (Just "") = Nothing@@ -382,3 +397,27 @@ dummyRemoteGitConfig :: IO RemoteGitConfig dummyRemoteGitConfig = atomically $  	extractRemoteGitConfig Git.Construct.fromUnknown "dummy"++type UnqualifiedConfigKey = B.ByteString++{- A global annex setting in git config. -}+annexConfig :: UnqualifiedConfigKey -> ConfigKey+annexConfig key = ConfigKey ("annex." <> key)++class RemoteNameable r where+	getRemoteName :: r -> RemoteName++instance RemoteNameable Git.Repo where+	getRemoteName r = fromMaybe "" (Git.remoteName r)++instance RemoteNameable RemoteName where+	 getRemoteName = id++{- A per-remote annex setting in git config. -}+remoteAnnexConfig :: RemoteNameable r => r -> UnqualifiedConfigKey -> ConfigKey+remoteAnnexConfig r key = remoteConfig r ("annex-" <> key)++{- A per-remote setting in git config. -}+remoteConfig :: RemoteNameable r => r -> UnqualifiedConfigKey -> ConfigKey+remoteConfig r key = ConfigKey $+	"remote." <> encodeBS' (getRemoteName r) <> "." <> key
Types/Remote.hs view
@@ -153,6 +153,9 @@ 	, remoteStateHandle :: RemoteStateHandle 	} +instance RemoteNameable (RemoteA a) where+	getRemoteName = name+ instance Show (RemoteA a) where 	show remote = "Remote { name =\"" ++ name remote ++ "\" }" 
Types/RemoteConfig.hs view
@@ -23,8 +23,9 @@  {- Before being used a RemoteConfig has to be parsed. -} data ParsedRemoteConfig = ParsedRemoteConfig-	(M.Map RemoteConfigField RemoteConfigValue)-	RemoteConfig+	{ parsedRemoteConfigMap :: M.Map RemoteConfigField RemoteConfigValue+	, unparsedRemoteConfig :: RemoteConfig+	}  {- Remotes can have configuration values of many types, so use Typeable  - to let them all be stored in here. -}
Upgrade.hs view
@@ -1,6 +1,6 @@ {- git-annex upgrade support  -- - Copyright 2010-2019 Joey Hess <id@joeyh.name>+ - Copyright 2010-2020 Joey Hess <id@joeyh.name>  -  - Licensed under the GNU AGPL version 3 or higher.  -}@@ -12,6 +12,8 @@ import Annex.Common import qualified Annex import qualified Git+import Config+import Config.Files import Annex.Version import Types.RepoVersion #ifndef mingw32_HOST_OS@@ -61,18 +63,26 @@ upgrade :: Bool -> RepoVersion -> Annex Bool upgrade automatic destversion = do 	upgraded <- go =<< getVersion-	when upgraded $-		setVersion destversion+	when upgraded+		postupgrade 	return upgraded   where 	go (Just v) 		| v >= destversion = return True-		| otherwise = ifM (up v)-			( go (Just (RepoVersion (fromRepoVersion v + 1)))-			, return False+		| otherwise = ifM upgradingRemote+			( upgraderemote+			, ifM (up v)+				( go (Just (RepoVersion (fromRepoVersion v + 1)))+				, return False+				) 			) 	go _ = return True +	postupgrade = ifM upgradingRemote+		( reloadConfig+		, setVersion destversion+		)+ #ifndef mingw32_HOST_OS 	up (RepoVersion 0) = Upgrade.V0.upgrade 	up (RepoVersion 1) = Upgrade.V1.upgrade@@ -87,3 +97,19 @@ 	up (RepoVersion 6) = Upgrade.V6.upgrade automatic 	up (RepoVersion 7) = Upgrade.V7.upgrade automatic 	up _ = return True++	-- Upgrade local remotes by running git-annex upgrade in them.+	-- This avoids complicating the upgrade code by needing to handle+	-- upgrading a git repo other than the current repo.+	upgraderemote = do+		rp <- fromRawFilePath <$> fromRepo Git.repoPath+		cmd <- liftIO readProgramFile+		liftIO $ boolSystem' cmd+			[ Param "upgrade"+			, Param "--quiet"+			, Param "--autoonly"+			]+			(\p -> p { cwd = Just rp })++upgradingRemote :: Annex Bool+upgradingRemote = isJust <$> fromRepo Git.remoteName
Upgrade/V1.hs view
@@ -17,6 +17,7 @@ import Annex.Common import Annex.Content import Annex.Link+import Annex.Perms import Types.Key import Logs.Presence import qualified Annex.Queue@@ -115,7 +116,7 @@ 		dest <- fromRepo $ logFile2 k 		dir <- fromRepo Upgrade.V2.gitStateDir 		let f = dir </> l-		liftIO $ createDirectoryIfMissing True (parentDir dest)+		createWorkTreeDirectory (parentDir dest) 		-- could just git mv, but this way deals with 		-- log files that are not checked into git, 		-- as well as merging with already upgraded
Upgrade/V5.hs view
@@ -10,7 +10,6 @@ module Upgrade.V5 where  import Annex.Common-import qualified Annex import Config import Config.Smudge import Annex.InodeSentinal@@ -84,7 +83,6 @@ 	 - 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
Upgrade/V5/Direct.hs view
@@ -19,7 +19,6 @@ ) where  import Annex.Common-import qualified Annex import qualified Git import qualified Git.Config import qualified Git.Ref@@ -35,7 +34,6 @@ 	setbare 	switchHEADBack 	setConfig (annexConfig "direct") val-	Annex.changeGitConfig $ \c -> c { annexDirect = False }   where 	val = Git.Config.boolConfig False 	coreworktree = ConfigKey "core.worktree"
Upgrade/V7.hs view
@@ -101,7 +101,7 @@ 	(l, cleanup) <- inRepo $ LsFiles.inodeCaches [top] 	forM_ l $ \case 		(_f, Nothing) -> giveup "Unable to parse git ls-files --debug output while upgrading git-annex sqlite databases."-		(f, Just ic) -> unlessM (liftIO $ isSymbolicLink <$> getSymbolicLinkStatus f) $ do+		(f, Just ic) -> unlessM (liftIO $ catchBoolIO $ isSymbolicLink <$> getSymbolicLinkStatus f) $ do 			catKeyFile (toRawFilePath f) >>= \case 				Nothing -> noop 				Just k -> do
Utility/Daemon.hs view
@@ -90,7 +90,6 @@  - Fails if the pid file is already locked by another process. -} lockPidFile :: FilePath -> IO () lockPidFile pidfile = do-	createDirectoryIfMissing True (parentDir pidfile) #ifndef mingw32_HOST_OS 	fd <- openFd pidfile ReadWrite (Just stdFileMode) defaultFileFlags 	locked <- catchMaybeIO $ setLock fd (WriteLock, AbsoluteSeek, 0, 0)
Utility/Directory.hs view
@@ -1,11 +1,12 @@ {- directory traversal and manipulation  -- - Copyright 2011-2014 Joey Hess <id@joeyh.name>+ - Copyright 2011-2020 Joey Hess <id@joeyh.name>  -  - License: BSD-2-clause  -}  {-# LANGUAGE CPP #-}+{-# LANGUAGE LambdaCase #-} {-# OPTIONS_GHC -fno-warn-tabs #-}  module Utility.Directory (@@ -18,7 +19,9 @@ import System.FilePath import System.PosixCompat.Files import Control.Applicative+import Control.Monad.IO.Class import System.IO.Unsafe (unsafeInterleaveIO)+import System.IO.Error import Data.Maybe import Prelude @@ -28,10 +31,12 @@ #endif  import Utility.SystemDirectory+import Utility.Path import Utility.Tmp import Utility.Exception import Utility.Monad import Utility.Applicative+import Utility.PartialPrelude  dirCruft :: FilePath -> Bool dirCruft "." = True@@ -154,3 +159,74 @@ #else 	go = removeFile file #endif++{- Like createDirectoryIfMissing True, but it will only create+ - missing parent directories up to but not including the directory+ - in the first parameter.+ -+ - For example, createDirectoryUnder "/tmp/foo" "/tmp/foo/bar/baz"+ - will create /tmp/foo/bar if necessary, but if /tmp/foo does not exist,+ - it will throw an exception.+ -+ - The exception thrown is the same that createDirectory throws if the+ - parent directory does not exist.+ -+ - If the second FilePath is not under the first+ - FilePath (or the same as it), it will fail with an exception+ - even if the second FilePath's parent directory already exists.+ -+ - Either or both of the FilePaths can be relative, or absolute.+ - They will be normalized as necessary.+ -+ - Note that, the second FilePath, if relative, is relative to the current+ - working directory, not to the first FilePath.+ -}+createDirectoryUnder :: FilePath -> FilePath -> IO ()+createDirectoryUnder topdir dir =+	createDirectoryUnder' topdir dir createDirectory++createDirectoryUnder'+	:: (MonadIO m, MonadCatch m)+	=> FilePath+	-> FilePath+	-> (FilePath -> m ())+	-> m ()+createDirectoryUnder' topdir dir0 mkdir = do+	p <- liftIO $ relPathDirToFile topdir dir0+	let dirs = splitDirectories p+	-- Catch cases where the dir is not beneath the topdir.+	-- If the relative path between them starts with "..",+	-- it's not. And on Windows, if they are on different drives,+	-- the path will not be relative.+	if headMaybe dirs == Just ".." || isAbsolute p+		then liftIO $ ioError $ customerror userErrorType+			("createDirectoryFrom: not located in " ++ topdir)+		-- If dir0 is the same as the topdir, don't try to create+		-- it, but make sure it does exist.+		else if null dirs+			then liftIO $ unlessM (doesDirectoryExist topdir) $+				ioError $ customerror doesNotExistErrorType+					"createDirectoryFrom: does not exist"+			else createdirs $+				map (topdir </>) (reverse (scanl1 (</>) dirs))+  where+	customerror t s = mkIOError t s Nothing (Just dir0)++	createdirs [] = pure ()+	createdirs (dir:[]) = createdir dir (liftIO . ioError)+	createdirs (dir:dirs) = createdir dir $ \_ -> do+		createdirs dirs+		createdir dir (liftIO . ioError)++	-- This is the same method used by createDirectoryIfMissing,+	-- in particular the handling of errors that occur when the+	-- directory already exists. See its source for explanation+	-- of several subtleties.+	createdir dir notexisthandler = tryIO (mkdir dir) >>= \case+		Right () -> pure ()+		Left e+			| isDoesNotExistError e -> notexisthandler e+			| isAlreadyExistsError e || isPermissionError e ->+				liftIO $ unlessM (doesDirectoryExist dir) $+					ioError e+			| otherwise -> liftIO $ ioError e
Utility/Hash.hs view
@@ -25,10 +25,10 @@ 	blake2bp_512, 	md5, 	md5s,-	prop_hashes_stable,+	props_hashes_stable, 	Mac(..), 	calcMac,-	prop_mac_stable,+	props_macs_stable, ) where  import qualified Data.ByteString as S@@ -111,31 +111,31 @@ md5s = hash  {- Check that all the hashes continue to hash the same. -}-prop_hashes_stable :: Bool-prop_hashes_stable = all (\(hasher, result) -> hasher foo == result)-	[ (show . sha1, "0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33")-	, (show . sha2_224, "0808f64e60d58979fcb676c96ec938270dea42445aeefcd3a4e6f8db")-	, (show . sha2_256, "2c26b46b68ffc68ff99b453c1d30413413422d706483bfa0f98a5e886266e7ae")-	, (show . sha2_384, "98c11ffdfdd540676b1a137cb1a22b2a70350c9a44171d6b1180c6be5cbb2ee3f79d532c8a1dd9ef2e8e08e752a3babb")-	, (show . sha2_512, "f7fbba6e0636f890e56fbbf3283e524c6fa3204ae298382d624741d0dc6638326e282c41be5e4254d8820772c5518a2c5a8c0c7f7eda19594a7eb539453e1ed7")-	, (show . skein256, "a04efd9a0aeed6ede40fe5ce0d9361ae7b7d88b524aa19917b9315f1ecf00d33")-	, (show . skein512, "fd8956898113510180aa4658e6c0ac85bd74fb47f4a4ba264a6b705d7a8e8526756e75aecda12cff4f1aca1a4c2830fbf57f458012a66b2b15a3dd7d251690a7")-	, (show . sha3_224, "f4f6779e153c391bbd29c95e72b0708e39d9166c7cea51d1f10ef58a")-	, (show . sha3_256, "76d3bc41c9f588f7fcd0d5bf4718f8f84b1c41b20882703100b9eb9413807c01")-	, (show . sha3_384, "665551928d13b7d84ee02734502b018d896a0fb87eed5adb4c87ba91bbd6489410e11b0fbcc06ed7d0ebad559e5d3bb5")-	, (show . sha3_512, "4bca2b137edc580fe50a88983ef860ebaca36c857b1f492839d6d7392452a63c82cbebc68e3b70a2a1480b4bb5d437a7cba6ecf9d89f9ff3ccd14cd6146ea7e7")-	, (show . blake2s_160, "52fb63154f958a5c56864597273ea759e52c6f00")-	, (show . blake2s_224, "9466668503ac415d87b8e1dfd7f348ab273ac1d5e4f774fced5fdb55")-	, (show . blake2s_256, "08d6cad88075de8f192db097573d0e829411cd91eb6ec65e8fc16c017edfdb74")-	, (show . blake2sp_224, "8492d356fbac99f046f55e114301f7596649cb590e5b083d1a19dcdb")-	, (show . blake2sp_256, "050dc5786037ea72cb9ed9d0324afcab03c97ec02e8c47368fc5dfb4cf49d8c9")-	, (show . blake2b_160, "983ceba2afea8694cc933336b27b907f90c53a88")-	, (show . blake2b_224, "853986b3fe231d795261b4fb530e1a9188db41e460ec4ca59aafef78")-	, (show . blake2b_256, "b8fe9f7f6255a6fa08f668ab632a8d081ad87983c77cd274e48ce450f0b349fd")-	, (show . blake2b_384, "e629ee880953d32c8877e479e3b4cb0a4c9d5805e2b34c675b5a5863c4ad7d64bb2a9b8257fac9d82d289b3d39eb9cc2")-	, (show . blake2b_512, "ca002330e69d3e6b84a46a56a6533fd79d51d97a3bb7cad6c2ff43b354185d6dc1e723fb3db4ae0737e120378424c714bb982d9dc5bbd7a0ab318240ddd18f8d")-	, (show . blake2bp_512, "8ca9ccee7946afcb686fe7556628b5ba1bf9a691da37ca58cd049354d99f37042c007427e5f219b9ab5063707ec6823872dee413ee014b4d02f2ebb6abb5f643")-	, (show . md5, "acbd18db4cc2f85cedef654fccc4a4d8")+props_hashes_stable :: [(String, Bool)]+props_hashes_stable = map (\(desc, hasher, result) -> (desc ++ " stable", hasher foo == result))+	[ ("sha1", show . sha1, "0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33")+	, ("sha2_224", show . sha2_224, "0808f64e60d58979fcb676c96ec938270dea42445aeefcd3a4e6f8db")+	, ("sha2_256", show . sha2_256, "2c26b46b68ffc68ff99b453c1d30413413422d706483bfa0f98a5e886266e7ae")+	, ("sha2_384", show . sha2_384, "98c11ffdfdd540676b1a137cb1a22b2a70350c9a44171d6b1180c6be5cbb2ee3f79d532c8a1dd9ef2e8e08e752a3babb")+	, ("sha2_512", show . sha2_512, "f7fbba6e0636f890e56fbbf3283e524c6fa3204ae298382d624741d0dc6638326e282c41be5e4254d8820772c5518a2c5a8c0c7f7eda19594a7eb539453e1ed7")+	, ("skein256", show . skein256, "a04efd9a0aeed6ede40fe5ce0d9361ae7b7d88b524aa19917b9315f1ecf00d33")+	, ("skein512", show . skein512, "fd8956898113510180aa4658e6c0ac85bd74fb47f4a4ba264a6b705d7a8e8526756e75aecda12cff4f1aca1a4c2830fbf57f458012a66b2b15a3dd7d251690a7")+	, ("sha3_224", show . sha3_224, "f4f6779e153c391bbd29c95e72b0708e39d9166c7cea51d1f10ef58a")+	, ("sha3_256", show . sha3_256, "76d3bc41c9f588f7fcd0d5bf4718f8f84b1c41b20882703100b9eb9413807c01")+	, ("sha3_384", show . sha3_384, "665551928d13b7d84ee02734502b018d896a0fb87eed5adb4c87ba91bbd6489410e11b0fbcc06ed7d0ebad559e5d3bb5")+	, ("sha3_512", show . sha3_512, "4bca2b137edc580fe50a88983ef860ebaca36c857b1f492839d6d7392452a63c82cbebc68e3b70a2a1480b4bb5d437a7cba6ecf9d89f9ff3ccd14cd6146ea7e7")+	, ("blake2s_160", show . blake2s_160, "52fb63154f958a5c56864597273ea759e52c6f00")+	, ("blake2s_224", show . blake2s_224, "9466668503ac415d87b8e1dfd7f348ab273ac1d5e4f774fced5fdb55")+	, ("blake2s_256", show . blake2s_256, "08d6cad88075de8f192db097573d0e829411cd91eb6ec65e8fc16c017edfdb74")+	, ("blake2sp_224", show . blake2sp_224, "8492d356fbac99f046f55e114301f7596649cb590e5b083d1a19dcdb")+	, ("blake2sp_256", show . blake2sp_256, "050dc5786037ea72cb9ed9d0324afcab03c97ec02e8c47368fc5dfb4cf49d8c9")+	, ("blake2b_160", show . blake2b_160, "983ceba2afea8694cc933336b27b907f90c53a88")+	, ("blake2b_224", show . blake2b_224, "853986b3fe231d795261b4fb530e1a9188db41e460ec4ca59aafef78")+	, ("blake2b_256", show . blake2b_256, "b8fe9f7f6255a6fa08f668ab632a8d081ad87983c77cd274e48ce450f0b349fd")+	, ("blake2b_384", show . blake2b_384, "e629ee880953d32c8877e479e3b4cb0a4c9d5805e2b34c675b5a5863c4ad7d64bb2a9b8257fac9d82d289b3d39eb9cc2")+	, ("blake2b_512", show . blake2b_512, "ca002330e69d3e6b84a46a56a6533fd79d51d97a3bb7cad6c2ff43b354185d6dc1e723fb3db4ae0737e120378424c714bb982d9dc5bbd7a0ab318240ddd18f8d")+	, ("blake2bp_512", show . blake2bp_512, "8ca9ccee7946afcb686fe7556628b5ba1bf9a691da37ca58cd049354d99f37042c007427e5f219b9ab5063707ec6823872dee413ee014b4d02f2ebb6abb5f643")+	, ("md5", show . md5, "acbd18db4cc2f85cedef654fccc4a4d8") 	]   where 	foo = L.fromChunks [T.encodeUtf8 $ T.pack "foo"]@@ -165,13 +165,13 @@ 	hmacWitnessAlg _ = hmac  -- Check that all the MACs continue to produce the same.-prop_mac_stable :: Bool-prop_mac_stable = all (\(mac, result) -> calcMac mac key msg == result)-	[ (HmacSha1, "46b4ec586117154dacd49d664e5d63fdc88efb51")-	, (HmacSha224, "4c1f774863acb63b7f6e9daa9b5c543fa0d5eccf61e3ffc3698eacdd")-	, (HmacSha256, "f9320baf0249169e73850cd6156ded0106e2bb6ad8cab01b7bbbebe6d1065317")-	, (HmacSha384, "3d10d391bee2364df2c55cf605759373e1b5a4ca9355d8f3fe42970471eca2e422a79271a0e857a69923839015877fc6")-	, (HmacSha512, "114682914c5d017dfe59fdc804118b56a3a652a0b8870759cf9e792ed7426b08197076bf7d01640b1b0684df79e4b67e37485669e8ce98dbab60445f0db94fce")+props_macs_stable :: [(String, Bool)]+props_macs_stable = map (\(desc, mac, result) -> (desc ++ " stable", calcMac mac key msg == result))+	[ ("HmacSha1", HmacSha1, "46b4ec586117154dacd49d664e5d63fdc88efb51")+	, ("HmacSha224", HmacSha224, "4c1f774863acb63b7f6e9daa9b5c543fa0d5eccf61e3ffc3698eacdd")+	, ("HmacSha256", HmacSha256, "f9320baf0249169e73850cd6156ded0106e2bb6ad8cab01b7bbbebe6d1065317")+	, ("HmacSha384", HmacSha384, "3d10d391bee2364df2c55cf605759373e1b5a4ca9355d8f3fe42970471eca2e422a79271a0e857a69923839015877fc6")+	, ("HmacSha512", HmacSha512, "114682914c5d017dfe59fdc804118b56a3a652a0b8870759cf9e792ed7426b08197076bf7d01640b1b0684df79e4b67e37485669e8ce98dbab60445f0db94fce") 	]   where 	key = T.encodeUtf8 $ T.pack "foo"
Utility/HumanTime.hs view
@@ -19,6 +19,7 @@ import Utility.PartialPrelude import Utility.QuickCheck +import Control.Monad.Fail as Fail (MonadFail(..)) import qualified Data.Map as M import Data.Time.Clock import Data.Time.Clock.POSIX (POSIXTime)@@ -44,7 +45,7 @@ daysToDuration i = Duration $ i * dsecs  {- Parses a human-input time duration, of the form "5h", "1m", "5h1m", etc -}-parseDuration :: Monad m => String -> m Duration+parseDuration :: MonadFail m => String -> m Duration parseDuration = maybe parsefail (return . Duration) . go 0   where 	go n [] = return n@@ -55,7 +56,7 @@ 				u <- M.lookup c unitmap 				go (n + num * u) rest 			_ -> return $ n + num-	parsefail = fail "duration parse error; expected eg \"5m\" or \"1h5m\""+	parsefail = Fail.fail "duration parse error; expected eg \"5m\" or \"1h5m\""  fromDuration :: Duration -> String fromDuration Duration { durationSeconds = d }
Utility/Path.hs view
@@ -41,7 +41,7 @@  import Utility.Monad import Utility.UserInfo-import Utility.Directory+import Utility.SystemDirectory import Utility.Split import Utility.FileSystemEncoding @@ -74,6 +74,8 @@  {- Makes a path absolute.  -+ - Also simplifies it using simplifyPath.+ -  - The first parameter is a base directory (ie, the cwd) to use if the path  - is not already absolute, and should itsef be absolute.  -@@ -124,12 +126,19 @@  {- Converts a filename into an absolute path.  -+ - Also simplifies it using simplifyPath.+ -  - Unlike Directory.canonicalizePath, this does not require the path  - already exists. -} absPath :: FilePath -> IO FilePath-absPath file = do-	cwd <- getCurrentDirectory-	return $ absPathFrom cwd file+absPath file+	-- Avoid unncessarily getting the current directory when the path+	-- is already absolute. absPathFrom uses simplifyPath+	-- so also used here for consistency.+	| isAbsolute file = return $ simplifyPath file+	| otherwise = do+		cwd <- getCurrentDirectory+		return $ absPathFrom cwd file  {- Constructs a relative path from the CWD to a file.  -
doc/git-annex-upgrade.mdwn view
@@ -8,7 +8,7 @@  # DESCRIPTION -Upgrades the repository.+Upgrades the repository to the latest version.  Each git-annex repository has an annex.version in its git configuration, that indicates the repository version. When an old repository version@@ -23,6 +23,13 @@ was only used by its author. It's expected that git-annex will always support upgrading from all past repository versions -- this is necessary to allow archives to be taken offline for years and later used.++# OPTIONS++* --autoonly++  Only do whatever automatic upgrade can be done, don't necessarily+  upgrade to the latest version. This is used internally by git-annex.  # SEE ALSO 
git-annex.cabal view
@@ -1,5 +1,5 @@ Name: git-annex-Version: 8.20200226+Version: 8.20200309 Cabal-Version: >= 1.8 License: AGPL-3 Maintainer: Joey Hess <id@joeyh.name>
stack.yaml view
@@ -15,16 +15,13 @@ packages: - '.' extra-deps:-- IfElse-0.85-- aws-0.21.1-- bloomfilter-2.0.1.0-- tasty-1.1.0.4-- tasty-rerun-1.1.13-- torrent-10000.1.1-- sandi-0.5-- http-client-0.5.14-- silently-1.2.5.1-- filepath-bytestring-1.4.2.1.1+ - IfElse-0.85+ - aws-0.21.1+ - bloomfilter-2.0.1.0+ - filepath-bytestring-1.4.2.1.6+ - sandi-0.5+ - tasty-rerun-1.1.17+ - torrent-10000.1.1 explicit-setup-deps:   git-annex: true-resolver: lts-13.29+resolver: lts-14.27