packages feed

git-annex 7.20191218 → 7.20191230

raw patch · 234 files changed

+2286/−1570 lines, 234 filesdep +filepath-bytestring

Dependencies added: filepath-bytestring

Files

Annex.hs view
@@ -214,7 +214,7 @@ new :: Git.Repo -> IO AnnexState new r = do 	r' <- Git.Config.read =<< Git.relPath r-	let c = extractGitConfig r'+	let c = extractGitConfig FromGitConfig r' 	newState c =<< fixupRepo r' c  {- Performs an action in the Annex monad from a starting state,@@ -325,7 +325,7 @@ 	r' <- liftIO $ adjuster r 	changeState $ \s -> s 		{ repo = r'-		, gitconfig = extractGitConfig r'+		, gitconfig = extractGitConfig FromGitConfig r' 		}  {- Adds an adjustment to the Repo data. Adjustments persist across reloads
Annex/AdjustedBranch.hs view
@@ -112,8 +112,8 @@ adjustToSymlink' :: (FilePath -> Key -> Git.Repo -> GitConfig -> IO FilePath) -> TreeItem -> Annex (Maybe TreeItem) adjustToSymlink' gitannexlink ti@(TreeItem f _m s) = catKey s >>= \case 	Just k -> do-		absf <- inRepo $ \r -> absPath $-			fromTopFilePath f r+		absf <- inRepo $ \r -> absPath $ +			fromRawFilePath $ fromTopFilePath f r 		linktarget <- calcRepo $ gitannexlink absf k 		Just . TreeItem f (fromTreeItemType TreeSymlink) 			<$> hashSymlink linktarget@@ -376,7 +376,7 @@ 	 -} 	changestomerge (Just updatedorig) = withOtherTmp $ \othertmpdir -> do 		tmpwt <- fromRepo gitAnnexMergeDir-		git_dir <- fromRepo Git.localGitDir+		git_dir <- fromRawFilePath <$> fromRepo Git.localGitDir 		withTmpDirIn othertmpdir "git" $ \tmpgit -> withWorkTreeRelated tmpgit $ 			withemptydir tmpwt $ withWorkTree tmpwt $ do 				liftIO $ writeFile (tmpgit </> "HEAD") (fromRef updatedorig)@@ -580,7 +580,7 @@ 	  where 		m = M.fromList $ map (\i@(TreeItem f' _ _) -> (norm f', i)) $ 			map diffTreeToTreeItem changes-		norm = normalise . getTopFilePath+		norm = normalise . fromRawFilePath . getTopFilePath  diffTreeToTreeItem :: Git.DiffTree.DiffTreeItem -> TreeItem diffTreeToTreeItem dti = TreeItem
Annex/AutoMerge.hs view
@@ -5,6 +5,8 @@  - Licensed under the GNU AGPL version 3 or higher.  -} +{-# LANGUAGE OverloadedStrings #-}+ module Annex.AutoMerge 	( autoMergeFrom 	, resolveMerge@@ -122,7 +124,7 @@ 		unless (null deleted) $ 			Annex.Queue.addCommand "rm" 				[Param "--quiet", Param "-f", Param "--"]-				deleted+				(map fromRawFilePath deleted) 		void $ liftIO cleanup2  	when merged $ do@@ -169,7 +171,7 @@ 		-- Neither side is annexed file; cannot resolve. 		(Nothing, Nothing) -> return ([], Nothing)   where-	file = LsFiles.unmergedFile u+	file = fromRawFilePath $ LsFiles.unmergedFile u  	getkey select =  		case select (LsFiles.unmergedSha u) of@@ -196,30 +198,30 @@  	stagefile :: FilePath -> Annex FilePath 	stagefile f-		| inoverlay = (</> f) <$> fromRepo Git.repoPath+		| inoverlay = (</> f) . fromRawFilePath <$> fromRepo Git.repoPath 		| otherwise = pure f  	makesymlink key dest = do 		l <- calcRepo $ gitAnnexLink dest key 		unless inoverlay $ replacewithsymlink dest l-		dest' <- stagefile dest+		dest' <- toRawFilePath <$> stagefile dest 		stageSymlink dest' =<< hashSymlink l  	replacewithsymlink dest link = withworktree dest $ \f ->-		replaceFile f $ makeGitLink link+		replaceFile f $ makeGitLink link . toRawFilePath  	makepointer key dest destmode = do 		unless inoverlay $  			unlessM (reuseOldFile unstagedmap key file dest) $ 				linkFromAnnex key dest destmode >>= \case 					LinkAnnexFailed -> liftIO $-						writePointerFile dest key destmode+						writePointerFile (toRawFilePath dest) key destmode 					_ -> noop-		dest' <- stagefile dest+		dest' <- toRawFilePath <$> stagefile dest 		stagePointerFile dest' destmode =<< hashPointerFile key 		unless inoverlay $ 			Database.Keys.addAssociatedFile key-				=<< inRepo (toTopFilePath dest)+				=<< inRepo (toTopFilePath (toRawFilePath dest))  	withworktree f a = a f @@ -239,7 +241,7 @@ 					Nothing -> noop 					Just sha -> do 						link <- catSymLinkTarget sha-						replacewithsymlink item link+						replacewithsymlink item (fromRawFilePath link) 			-- And when grafting in anything else vs a symlink, 			-- the work tree already contains what we want. 			(_, Just TreeSymlink) -> noop@@ -290,8 +292,8 @@ 	matchesresolved is i f 		| S.member f fs || S.member (conflictCruftBase f) fs = anyM id 			[ pure (S.member i is)-			, inks <$> isAnnexLink f-			, inks <$> liftIO (isPointerFile f)+			, inks <$> isAnnexLink (toRawFilePath f)+			, inks <$> liftIO (isPointerFile (toRawFilePath f)) 			] 		| otherwise = return False @@ -328,13 +330,13 @@  type InodeMap = M.Map InodeCacheKey FilePath -inodeMap :: Annex ([FilePath], IO Bool) -> Annex InodeMap+inodeMap :: Annex ([RawFilePath], IO Bool) -> Annex InodeMap inodeMap getfiles = do 	(fs, cleanup) <- getfiles 	fsis <- forM fs $ \f -> do 		mi <- withTSDelta (liftIO . genInodeCache f) 		return $ case mi of 			Nothing -> Nothing-			Just i -> Just (inodeCacheToKey Strongly i, f)+			Just i -> Just (inodeCacheToKey Strongly i, fromRawFilePath f) 	void $ liftIO cleanup 	return $ M.fromList $ catMaybes fsis
Annex/Branch.hs view
@@ -215,7 +215,7 @@  - content is returned.  -  - Returns an empty string if the file doesn't exist yet. -}-get :: FilePath -> Annex L.ByteString+get :: RawFilePath -> Annex L.ByteString get file = do 	update 	getLocal file@@ -224,21 +224,21 @@  - reflect changes in remotes.  - (Changing the value this returns, and then merging is always the  - same as using get, and then changing its value.) -}-getLocal :: FilePath -> Annex L.ByteString+getLocal :: RawFilePath -> Annex L.ByteString getLocal file = go =<< getJournalFileStale file   where 	go (Just journalcontent) = return journalcontent 	go Nothing = getRef fullname file  {- Gets the content of a file as staged in the branch's index. -}-getStaged :: FilePath -> Annex L.ByteString+getStaged :: RawFilePath -> Annex L.ByteString getStaged = getRef indexref   where 	-- This makes git cat-file be run with ":file", 	-- so it looks at the index. 	indexref = Ref "" -getHistorical :: RefDate -> FilePath -> Annex L.ByteString+getHistorical :: RefDate -> RawFilePath -> Annex L.ByteString getHistorical date file = 	-- This check avoids some ugly error messages when the reflog 	-- is empty.@@ -247,7 +247,7 @@ 		, getRef (Git.Ref.dateRef fullname date) file 		) -getRef :: Ref -> FilePath -> Annex L.ByteString+getRef :: Ref -> RawFilePath -> Annex L.ByteString getRef ref file = withIndex $ catFile ref file  {- Applies a function to modify the content of a file.@@ -255,11 +255,11 @@  - Note that this does not cause the branch to be merged, it only  - modifes the current content of the file on the branch.  -}-change :: Journalable content => FilePath -> (L.ByteString -> content) -> Annex ()+change :: Journalable content => RawFilePath -> (L.ByteString -> content) -> Annex () change file f = lockJournal $ \jl -> f <$> getLocal file >>= set jl file  {- Applies a function which can modify the content of a file, or not. -}-maybeChange :: Journalable content => FilePath -> (L.ByteString -> Maybe content) -> Annex ()+maybeChange :: Journalable content => RawFilePath -> (L.ByteString -> Maybe content) -> Annex () maybeChange file f = lockJournal $ \jl -> do 	v <- getLocal file 	case f v of@@ -269,7 +269,7 @@ 		_ -> noop  {- Records new content of a file into the journal -}-set :: Journalable content => JournalLocked -> FilePath -> content -> Annex ()+set :: Journalable content => JournalLocked -> RawFilePath -> content -> Annex () set = setJournalFile  {- Commit message used when making a commit of whatever data has changed@@ -353,23 +353,23 @@  {- Lists all files on the branch. including ones in the journal  - that have not been committed yet. There may be duplicates in the list. -}-files :: Annex [FilePath]+files :: Annex [RawFilePath] files = do 	update 	-- ++ forces the content of the first list to be buffered in memory, 	-- so use getJournalledFilesStale which should be much smaller most 	-- of the time. branchFiles will stream as the list is consumed. 	(++)-		<$> getJournalledFilesStale+		<$> (map toRawFilePath <$> getJournalledFilesStale) 		<*> branchFiles  {- Files in the branch, not including any from journalled changes,  - and without updating the branch. -}-branchFiles :: Annex [FilePath]+branchFiles :: Annex [RawFilePath] branchFiles = withIndex $ inRepo branchFiles' -branchFiles' :: Git.Repo -> IO [FilePath]-branchFiles' = Git.Command.pipeNullSplitZombie+branchFiles' :: Git.Repo -> IO [RawFilePath]+branchFiles' = Git.Command.pipeNullSplitZombie' 	(lsTreeParams Git.LsTree.LsTreeRecursive fullname [Param "--name-only"])  {- Populates the branch's index file with the current branch contents.@@ -482,7 +482,7 @@ 				sha <- Git.HashObject.hashFile h path 				hPutStrLn jlogh file 				streamer $ Git.UpdateIndex.updateIndexLine-					sha TreeFile (asTopFilePath $ fileJournal file)+					sha TreeFile (asTopFilePath $ fileJournal $ toRawFilePath file) 			genstream dir h jh jlogh streamer 	-- Clean up the staged files, as listed in the temp log file. 	-- The temp file is used to avoid needing to buffer all the@@ -593,7 +593,7 @@ 			if L.null content' 				then do 					Annex.Queue.addUpdateIndex-						=<< inRepo (Git.UpdateIndex.unstageFile file)+						=<< inRepo (Git.UpdateIndex.unstageFile (fromRawFilePath file)) 					-- File is deleted; can't run any other 					-- transitions on it. 					return ()
Annex/Branch/Transitions.hs view
@@ -34,7 +34,7 @@ 	= ChangeFile Builder 	| PreserveFile -type TransitionCalculator = TrustMap -> M.Map UUID RemoteConfig -> FilePath -> L.ByteString -> FileTransition+type TransitionCalculator = TrustMap -> M.Map UUID RemoteConfig -> RawFilePath -> L.ByteString -> FileTransition  getTransitionCalculator :: Transition -> Maybe TransitionCalculator getTransitionCalculator ForgetGitHistory = Nothing
Annex/CatFile.hs view
@@ -1,6 +1,6 @@ {- git cat-file interface, with handle automatically stored in the Annex monad  -- - Copyright 2011-2018 Joey Hess <id@joeyh.name>+ - Copyright 2011-2019 Joey Hess <id@joeyh.name>  -  - Licensed under the GNU AGPL version 3 or higher.  -}@@ -16,6 +16,7 @@ 	catObjectMetaData, 	catFileStop, 	catKey,+	catKey', 	catSymLinkTarget, 	catKeyFile, 	catKeyFileHEAD,@@ -39,12 +40,12 @@ import Annex.CurrentBranch import Types.AdjustedBranch -catFile :: Git.Branch -> FilePath -> Annex L.ByteString+catFile :: Git.Branch -> RawFilePath -> Annex L.ByteString catFile branch file = do 	h <- catFileHandle 	liftIO $ Git.CatFile.catFile h branch file -catFileDetails :: Git.Branch -> FilePath -> Annex (Maybe (L.ByteString, Sha, ObjectType))+catFileDetails :: Git.Branch -> RawFilePath -> Annex (Maybe (L.ByteString, Sha, ObjectType)) catFileDetails branch file = do 	h <- catFileHandle 	liftIO $ Git.CatFile.catFileDetails h branch file@@ -54,7 +55,7 @@ 	h <- catFileHandle 	liftIO $ Git.CatFile.catObject h ref -catObjectMetaData :: Git.Ref -> Annex (Maybe (Integer, ObjectType))+catObjectMetaData :: Git.Ref -> Annex (Maybe (Sha, Integer, ObjectType)) catObjectMetaData ref = do 	h <- catFileHandle 	liftIO $ Git.CatFile.catObjectMetaData h ref@@ -99,18 +100,20 @@  {- From ref to a symlink or a pointer file, get the key. -} catKey :: Ref -> Annex (Maybe Key)-catKey ref = go =<< catObjectMetaData ref-  where-	go (Just (sz, _))-		-- Avoid catting large files, that cannot be symlinks or-		-- pointer files, which would require buffering their-		-- content in memory, as well as a lot of IO.-		| sz <= maxPointerSz = parseLinkTargetOrPointer . L.toStrict <$> catObject ref-	go _ = return Nothing+catKey ref = catKey' ref =<< catObjectMetaData ref +catKey' :: Ref -> Maybe (Sha, Integer, ObjectType) -> Annex (Maybe Key)+catKey' ref (Just (_, sz, _))+	-- Avoid catting large files, that cannot be symlinks or+	-- pointer files, which would require buffering their+	-- content in memory, as well as a lot of IO.+	| sz <= maxPointerSz =+		parseLinkTargetOrPointer . L.toStrict <$> catObject ref+catKey' _ _ = return Nothing+ {- Gets a symlink target. -}-catSymLinkTarget :: Sha -> Annex String-catSymLinkTarget sha = fromInternalGitPath . decodeBL <$> get+catSymLinkTarget :: Sha -> Annex RawFilePath+catSymLinkTarget sha = fromInternalGitPath . L.toStrict <$> get   where 	-- Avoid buffering the whole file content, which might be large. 	-- 8192 is enough if it really is a symlink.@@ -137,24 +140,24 @@  -  - So, this gets info from the index, unless running as a daemon.  -}-catKeyFile :: FilePath -> Annex (Maybe Key)+catKeyFile :: RawFilePath -> Annex (Maybe Key) catKeyFile f = ifM (Annex.getState Annex.daemon) 	( catKeyFileHEAD f 	, catKey $ Git.Ref.fileRef f 	) -catKeyFileHEAD :: FilePath -> Annex (Maybe Key)+catKeyFileHEAD :: RawFilePath -> Annex (Maybe Key) catKeyFileHEAD f = catKey $ Git.Ref.fileFromRef Git.Ref.headRef f  {- Look in the original branch from whence an adjusted branch is based  - to find the file. But only when the adjustment hides some files. -}-catKeyFileHidden :: FilePath -> CurrBranch -> Annex (Maybe Key) +catKeyFileHidden :: RawFilePath -> CurrBranch -> Annex (Maybe Key)  catKeyFileHidden = hiddenCat catKey -catObjectMetaDataHidden :: FilePath -> CurrBranch -> Annex (Maybe (Integer, ObjectType))+catObjectMetaDataHidden :: RawFilePath -> CurrBranch -> Annex (Maybe (Sha, Integer, ObjectType)) catObjectMetaDataHidden = hiddenCat catObjectMetaData -hiddenCat :: (Ref -> Annex (Maybe a)) -> FilePath -> CurrBranch -> Annex (Maybe a)+hiddenCat :: (Ref -> Annex (Maybe a)) -> RawFilePath -> CurrBranch -> Annex (Maybe a) hiddenCat a f (Just origbranch, Just adj) 	| adjustmentHidesFiles adj = a (Git.Ref.fileFromRef origbranch f) hiddenCat _ _ _ = return Nothing
Annex/ChangedRefs.hs view
@@ -76,7 +76,7 @@ 	chan <- liftIO $ newTBMChanIO 100 	 	g <- gitRepo-	let refdir = Git.localGitDir g </> "refs"+	let refdir = fromRawFilePath (Git.localGitDir g) </> "refs" 	liftIO $ createDirectoryIfMissing True refdir  	let notifyhook = Just $ notifyHook chan
Annex/Content.hs view
@@ -89,17 +89,20 @@ import Annex.Content.PointerFile import Annex.Concurrent import Types.WorkerPool+import qualified Utility.RawFilePath as R +import qualified System.FilePath.ByteString as P+ {- Checks if a given key's content is currently present. -} inAnnex :: Key -> Annex Bool-inAnnex key = inAnnexCheck key $ liftIO . doesFileExist+inAnnex key = inAnnexCheck key $ liftIO . R.doesPathExist  {- Runs an arbitrary check on a key's content. -}-inAnnexCheck :: Key -> (FilePath -> Annex Bool) -> Annex Bool+inAnnexCheck :: Key -> (RawFilePath -> Annex Bool) -> Annex Bool inAnnexCheck key check = inAnnex' id False check key  {- inAnnex that performs an arbitrary check of the key's content. -}-inAnnex' :: (a -> Bool) -> a -> (FilePath -> Annex a) -> Key -> Annex a+inAnnex' :: (a -> Bool) -> a -> (RawFilePath -> Annex a) -> Key -> Annex a inAnnex' isgood bad check key = withObjectLoc key $ \loc -> do 	r <- check loc 	if isgood r@@ -120,12 +123,15 @@ {- Like inAnnex, checks if the object file for a key exists,  - but there are no guarantees it has the right content. -} objectFileExists :: Key -> Annex Bool-objectFileExists key = calcRepo (gitAnnexLocation key) >>= liftIO . doesFileExist+objectFileExists key =+	calcRepo (gitAnnexLocation key)+		>>= liftIO . R.doesPathExist  {- A safer check; the key's content must not only be present, but  - is not in the process of being removed. -} inAnnexSafe :: Key -> Annex (Maybe Bool)-inAnnexSafe key = inAnnex' (fromMaybe True) (Just False) go key+inAnnexSafe key = +	inAnnex' (fromMaybe True) (Just False) (go . fromRawFilePath) key   where 	is_locked = Nothing 	is_unlocked = Just True@@ -246,7 +252,7 @@  lockContentUsing :: ContentLocker -> Key -> Annex a -> Annex a lockContentUsing locker key a = do-	contentfile <- calcRepo $ gitAnnexLocation key+	contentfile <- fromRawFilePath <$> calcRepo (gitAnnexLocation key) 	lockfile <- contentLockFile key 	bracket 		(lock contentfile lockfile)@@ -474,11 +480,11 @@ 	, return False 	)   where-	storeobject dest = ifM (liftIO $ doesFileExist dest)+	storeobject dest = ifM (liftIO $ R.doesPathExist dest) 		( alreadyhave-		, modifyContent dest $ do+		, modifyContent dest' $ do 			freezeContent src-			liftIO $ moveFile src dest+			liftIO $ moveFile src dest' 			g <- Annex.gitRepo  			fs <- map (`fromTopFilePath` g) 				<$> Database.Keys.getAssociatedFiles key@@ -486,6 +492,8 @@ 				ics <- mapM (populatePointerFile (Restage True) key dest) fs 				Database.Keys.storeInodeCaches' key [dest] (catMaybes ics) 		)+	  where+		dest' = fromRawFilePath dest 	alreadyhave = liftIO $ removeFile src  checkSecureHashes :: Key -> Annex Bool@@ -505,7 +513,7 @@ linkToAnnex :: Key -> FilePath -> Maybe InodeCache -> Annex LinkAnnexResult linkToAnnex key src srcic = ifM (checkSecureHashes key) 	( do-		dest <- calcRepo (gitAnnexLocation key)+		dest <- fromRawFilePath <$> calcRepo (gitAnnexLocation key) 		modifyContent dest $ linkAnnex To key src srcic dest Nothing 	, return LinkAnnexFailed 	)@@ -515,7 +523,7 @@ linkFromAnnex key dest destmode = do 	src <- calcRepo (gitAnnexLocation key) 	srcic <- withTSDelta (liftIO . genInodeCache src)-	linkAnnex From key src srcic dest destmode+	linkAnnex From key (fromRawFilePath src) srcic dest destmode  data FromTo = From | To @@ -534,7 +542,7 @@ linkAnnex :: FromTo -> Key -> FilePath -> Maybe InodeCache -> FilePath -> Maybe FileMode -> Annex LinkAnnexResult linkAnnex _ _ _ Nothing _ _ = return LinkAnnexFailed linkAnnex fromto key src (Just srcic) dest destmode =-	withTSDelta (liftIO . genInodeCache dest) >>= \case+	withTSDelta (liftIO . genInodeCache dest') >>= \case 		Just destic -> do 			cs <- Database.Keys.getInodeCaches key 			if null cs@@ -551,12 +559,13 @@ 						Linked -> noop 				checksrcunchanged   where+	dest' = toRawFilePath dest 	failed = do 		Database.Keys.addInodeCaches key [srcic] 		return LinkAnnexFailed-	checksrcunchanged = withTSDelta (liftIO . genInodeCache src) >>= \case+	checksrcunchanged = withTSDelta (liftIO . genInodeCache (toRawFilePath src)) >>= \case 		Just srcic' | compareStrong srcic srcic' -> do-			destic <- withTSDelta (liftIO . genInodeCache dest)+			destic <- withTSDelta (liftIO . genInodeCache dest') 			Database.Keys.addInodeCaches key $ 				catMaybes [destic, Just srcic] 			return LinkAnnexOk@@ -567,7 +576,7 @@ {- Removes the annex object file for a key. Lowlevel. -} unlinkAnnex :: Key -> Annex () unlinkAnnex key = do-	obj <- calcRepo $ gitAnnexLocation key+	obj <- fromRawFilePath <$> calcRepo (gitAnnexLocation key) 	modifyContent obj $ do 		secureErase obj 		liftIO $ nukeFile obj@@ -616,15 +625,15 @@ 		else pure cache 	return $ if null cache' 		then Nothing-		else Just (f, sameInodeCache f cache')+		else Just (fromRawFilePath f, sameInodeCache f cache')  {- Performs an action, passing it the location to use for a key's content. -}-withObjectLoc :: Key -> (FilePath -> Annex a) -> Annex a+withObjectLoc :: Key -> (RawFilePath -> Annex a) -> Annex a withObjectLoc key a = a =<< calcRepo (gitAnnexLocation key)  cleanObjectLoc :: Key -> Annex () -> Annex () cleanObjectLoc key cleaner = do-	file <- calcRepo $ gitAnnexLocation key+	file <- fromRawFilePath <$> calcRepo (gitAnnexLocation key) 	void $ tryIO $ thawContentDir file 	cleaner 	liftIO $ removeparents file (3 :: Int)@@ -640,8 +649,9 @@ removeAnnex :: ContentRemovalLock -> Annex () removeAnnex (ContentRemovalLock key) = withObjectLoc key $ \file -> 	cleanObjectLoc key $ do-		secureErase file-		liftIO $ nukeFile file+		let file' = fromRawFilePath file+		secureErase file'+		liftIO $ nukeFile file' 		g <- Annex.gitRepo  		mapM_ (\f -> void $ tryIO $ resetpointer $ fromTopFilePath f g) 			=<< Database.Keys.getAssociatedFiles key@@ -655,7 +665,7 @@ 		-- If it was a hard link to the annex object, 		-- that object might have been frozen as part of the 		-- removal process, so thaw it.-		, void $ tryIO $ thawContent file+		, void $ tryIO $ thawContent $ fromRawFilePath file 		)  {- Check if a file contains the unmodified content of the key.@@ -663,12 +673,12 @@  - The expensive way to tell is to do a verification of its content.  - The cheaper way is to see if the InodeCache for the key matches the  - file. -}-isUnmodified :: Key -> FilePath -> Annex Bool+isUnmodified :: Key -> RawFilePath -> Annex Bool isUnmodified key f = go =<< geti   where 	go Nothing = return False 	go (Just fc) = isUnmodifiedCheap' key fc <||> expensivecheck fc-	expensivecheck fc = ifM (verifyKeyContent RetrievalAllKeysSecure AlwaysVerify UnVerified key f)+	expensivecheck fc = ifM (verifyKeyContent RetrievalAllKeysSecure AlwaysVerify UnVerified key (fromRawFilePath f)) 		( do 			-- The file could have been modified while it was 			-- being verified. Detect that.@@ -691,7 +701,7 @@  - this may report a false positive when repeated edits are made to a file  - within a small time window (eg 1 second).  -}-isUnmodifiedCheap :: Key -> FilePath -> Annex Bool+isUnmodifiedCheap :: Key -> RawFilePath -> Annex Bool isUnmodifiedCheap key f = maybe (return False) (isUnmodifiedCheap' key)  	=<< withTSDelta (liftIO . genInodeCache f) @@ -703,7 +713,7 @@  - returns the file it was moved to. -} moveBad :: Key -> Annex FilePath moveBad key = do-	src <- calcRepo $ gitAnnexLocation key+	src <- fromRawFilePath <$> calcRepo (gitAnnexLocation key) 	bad <- fromRepo gitAnnexBadDir 	let dest = bad </> takeFileName src 	createAnnexDirectory (parentDir dest)@@ -734,7 +744,7 @@ 		if depth < 2 			then do 				contents' <- filterM (present s) contents-				let keys = mapMaybe (fileKey . takeFileName) contents'+				let keys = mapMaybe (fileKey . P.takeFileName . toRawFilePath) contents' 				continue keys [] 			else do 				let deeper = walk s (depth - 1)@@ -791,7 +801,7 @@ 	copy = ifM (liftIO $ doesFileExist file) 		( return True 		, do-			s <- calcRepo $ gitAnnexLocation key+			s <- fromRawFilePath <$> (calcRepo $ gitAnnexLocation key) 			liftIO $ ifM (doesFileExist s) 				( copyFileExternal CopyTimeStamps s file 				, return False@@ -808,7 +818,7 @@ 			contents <- liftIO $ getDirectoryContents dir 			files <- liftIO $ filterM doesFileExist $ 				map (dir </>) contents-			return $ mapMaybe (fileKey . takeFileName) files+			return $ mapMaybe (fileKey . P.takeFileName . toRawFilePath) files 		, return [] 		) @@ -827,7 +837,8 @@  	dir <- fromRepo dirspec 	forM_ dups $ \k ->-		pruneTmpWorkDirBefore (dir </> keyFile k) (liftIO . removeFile)+		pruneTmpWorkDirBefore (dir </> fromRawFilePath (keyFile k))+			(liftIO . removeFile)  	if nottransferred 		then do
Annex/Content/LowLevel.hs view
@@ -128,7 +128,7 @@ 			_ -> return True 	)   where-	dir = maybe (fromRepo gitAnnexDir) return destdir+	dir = maybe (fromRawFilePath <$> fromRepo gitAnnexDir) return destdir  needMoreDiskSpace :: Integer -> String needMoreDiskSpace n = "not enough free space, need " ++ 
Annex/Content/PointerFile.hs view
@@ -30,17 +30,19 @@  -  - Returns an InodeCache if it populated the pointer file.  -}-populatePointerFile :: Restage -> Key -> FilePath -> FilePath -> Annex (Maybe InodeCache)+populatePointerFile :: Restage -> Key -> RawFilePath -> RawFilePath -> Annex (Maybe InodeCache) populatePointerFile restage k obj f = go =<< liftIO (isPointerFile f)   where 	go (Just k') | k == k' = do-		destmode <- liftIO $ catchMaybeIO $ fileMode <$> getFileStatus f-		liftIO $ nukeFile f-		(ic, populated) <- replaceFile f $ \tmp -> do-			ok <- linkOrCopy k obj tmp destmode >>= \case+		let f' = fromRawFilePath f+		destmode <- liftIO $ catchMaybeIO $ fileMode <$> getFileStatus f'+		liftIO $ nukeFile f'+		(ic, populated) <- replaceFile f' $ \tmp -> do+			let tmp' = toRawFilePath tmp+			ok <- linkOrCopy k (fromRawFilePath obj) tmp destmode >>= \case 				Just _ -> thawContent tmp >> return True-				Nothing -> liftIO (writePointerFile tmp k destmode) >> return False-			ic <- withTSDelta (liftIO . genInodeCache tmp)+				Nothing -> liftIO (writePointerFile tmp' k destmode) >> return False+			ic <- withTSDelta (liftIO . genInodeCache tmp') 			return (ic, ok) 		maybe noop (restagePointerFile restage f) ic 		if populated@@ -51,14 +53,15 @@ {- Removes the content from a pointer file, replacing it with a pointer.  -  - Does not check if the pointer file is modified. -}-depopulatePointerFile :: Key -> FilePath -> Annex ()+depopulatePointerFile :: Key -> RawFilePath -> Annex () depopulatePointerFile key file = do-	st <- liftIO $ catchMaybeIO $ getFileStatus file+	let file' = fromRawFilePath file+	st <- liftIO $ catchMaybeIO $ getFileStatus file' 	let mode = fmap fileMode st-	secureErase file-	liftIO $ nukeFile file-	ic <- replaceFile file $ \tmp -> do-		liftIO $ writePointerFile tmp key mode+	secureErase file'+	liftIO $ nukeFile file'+	ic <- replaceFile file' $ \tmp -> do+		liftIO $ writePointerFile (toRawFilePath tmp) key mode #if ! defined(mingw32_HOST_OS) 		-- Don't advance mtime; this avoids unncessary re-smudging 		-- by git in some cases.@@ -66,5 +69,5 @@ 			(\t -> touch tmp t False) 			(fmap modificationTimeHiRes st) #endif-		withTSDelta (liftIO . genInodeCache tmp)+		withTSDelta (liftIO . genInodeCache (toRawFilePath tmp)) 	maybe noop (restagePointerFile (Restage True) file) ic
Annex/Difference.hs view
@@ -54,5 +54,5 @@ 					else return ds 			) 		forM_ (listDifferences ds') $ \d ->-			setConfig (ConfigKey $ differenceConfigKey d) (differenceConfigVal d)+			setConfig (differenceConfigKey d) (differenceConfigVal d) 		recordDifferences ds' u
Annex/DirHashes.hs view
@@ -1,6 +1,6 @@ {- git-annex file locations  -- - Copyright 2010-2017 Joey Hess <id@joeyh.name>+ - Copyright 2010-2019 Joey Hess <id@joeyh.name>  -  - Licensed under the GNU AGPL version 3 or higher.  -}@@ -19,7 +19,10 @@  import Data.Default import Data.Bits-import qualified Data.ByteArray+import qualified Data.ByteArray as BA+import qualified Data.ByteArray.Encoding as BA+import qualified Data.ByteString as S+import qualified System.FilePath.ByteString as P  import Common import Key@@ -28,7 +31,7 @@ import Utility.Hash import Utility.MD5 -type Hasher = Key -> FilePath+type Hasher = Key -> RawFilePath  -- Number of hash levels to use. 2 is the default. newtype HashLevels = HashLevels Int@@ -47,7 +50,7 @@ 	| hasDifference d (annexDifferences config) = HashLevels 1 	| otherwise = def -branchHashDir :: GitConfig -> Key -> String+branchHashDir :: GitConfig -> Key -> S.ByteString branchHashDir = hashDirLower . branchHashLevels  {- Two different directory hashes may be used. The mixed case hash@@ -60,19 +63,26 @@ dirHashes :: [HashLevels -> Hasher] dirHashes = [hashDirLower, hashDirMixed] -hashDirs :: HashLevels -> Int -> String -> FilePath-hashDirs (HashLevels 1) sz s = addTrailingPathSeparator $ take sz s-hashDirs _ sz s = addTrailingPathSeparator $ take sz s </> drop sz s+hashDirs :: HashLevels -> Int -> S.ByteString -> RawFilePath+hashDirs (HashLevels 1) sz s = P.addTrailingPathSeparator $ S.take sz s+hashDirs _ sz s = P.addTrailingPathSeparator $ h P.</> t+  where+	(h, t) = S.splitAt sz s  hashDirLower :: HashLevels -> Hasher-hashDirLower n k = hashDirs n 3 $ take 6 $ show $ md5s $ serializeKey' $ nonChunkKey k+hashDirLower n k = hashDirs n 3 $ S.pack $ take 6 $ conv $+	md5s $ serializeKey' $ nonChunkKey k+  where+	conv v = BA.unpack $+		(BA.convertToBase BA.Base16 v :: BA.Bytes)  {- This was originally using Data.Hash.MD5 from MissingH. This new version - is faster, but ugly as it has to replicate the 4 Word32's that produced. -} hashDirMixed :: HashLevels -> Hasher-hashDirMixed n k = hashDirs n 2 $ take 4 $ concatMap display_32bits_as_dir $-	encodeWord32 $ map fromIntegral $ Data.ByteArray.unpack $-		Utility.Hash.md5s $ serializeKey' $ nonChunkKey k+hashDirMixed n k = hashDirs n 2 $ S.pack $ take 4 $+	concatMap display_32bits_as_dir $+		encodeWord32 $ map fromIntegral $ BA.unpack $+			Utility.Hash.md5s $ serializeKey' $ nonChunkKey k   where 	encodeWord32 (b1:b2:b3:b4:rest) = 		(shiftL b4 24 .|. shiftL b3 16 .|. shiftL b2 8 .|. b1)
Annex/Drop.hs view
@@ -49,7 +49,8 @@ handleDropsFrom :: [UUID] -> [Remote] -> Reason -> Bool -> Key -> AssociatedFile -> [VerifiedCopy] -> (CommandStart -> CommandCleanup) -> Annex () handleDropsFrom locs rs reason fromhere key afile preverified runner = do 	g <- Annex.gitRepo-	l <- map (`fromTopFilePath` g) <$> Database.Keys.getAssociatedFiles key+	l <- map (`fromTopFilePath` g)+		<$> Database.Keys.getAssociatedFiles key 	let fs = case afile of 		AssociatedFile (Just f) -> nub (f : l) 		AssociatedFile Nothing -> l@@ -62,7 +63,7 @@ 		(untrusted, have) <- trustPartition UnTrusted locs 		numcopies <- if null fs 			then getNumCopies-			else maximum <$> mapM getFileNumCopies fs+			else maximum <$> mapM (getFileNumCopies . fromRawFilePath) fs 		return (NumCopies (length have), numcopies, S.fromList untrusted)  	{- Check that we have enough copies still to drop the content.@@ -107,7 +108,7 @@ 					[ "dropped" 					, case afile of 						AssociatedFile Nothing -> serializeKey key-						AssociatedFile (Just af) -> af+						AssociatedFile (Just af) -> fromRawFilePath af 					, "(from " ++ maybe "here" show u ++ ")" 					, "(copies now " ++ show (fromNumCopies have - 1) ++ ")" 					, ": " ++ reason
Annex/Environment.hs view
@@ -5,6 +5,8 @@  - Licensed under the GNU AGPL version 3 or higher.  -} +{-# LANGUAGE OverloadedStrings #-}+ module Annex.Environment where  import Annex.Common@@ -45,6 +47,6 @@   where 	retry _ = do 		name <- liftIO $ either (const "unknown") id <$> myUserName-		setConfig (ConfigKey "user.name") name-		setConfig (ConfigKey "user.email") name+		setConfig "user.name" name+		setConfig "user.email" name 		a
Annex/FileMatcher.hs view
@@ -20,8 +20,12 @@ 	preferredContentParser, 	ParseToken, 	parsedToMatcher,-	mkLargeFilesParser,+	mkMatchExpressionParser, 	largeFilesMatcher,+	AddUnlockedMatcher,+	addUnlockedMatcher,+	checkAddUnlockedMatcher,+	module Types.FileMatcher ) where  import qualified Data.Map as M@@ -30,12 +34,14 @@ import Limit import Utility.Matcher import Types.Group-import qualified Annex import Types.FileMatcher+import Types.GitConfig+import Config.GitConfig import Git.FilePath import Types.Remote (RemoteConfig) import Annex.CheckAttr import Git.CheckAttr (unspecifiedAttr)+import qualified Git.Config #ifdef WITH_MAGICMIME import Annex.Magic #endif@@ -54,7 +60,7 @@ 	matcher <- getmatcher file 	checkMatcher matcher Nothing afile S.empty notconfigured d   where-	afile = AssociatedFile (Just file)+	afile = AssociatedFile (Just (toRawFilePath file)) 	-- checkMatcher will never use this, because afile is provided. 	d = return True @@ -72,7 +78,7 @@ checkMatcher' matcher mi notpresent = 	matchMrun matcher $ \a -> a notpresent mi -fileMatchInfo :: FilePath -> Annex MatchInfo+fileMatchInfo :: RawFilePath -> Annex MatchInfo fileMatchInfo file = do 	matchfile <- getTopFilePath <$> inRepo (toTopFilePath file) 	return $ MatchingFile FileInfo@@ -173,8 +179,8 @@ preferredContentParser :: [ParseToken (MatchFiles Annex)] -> String -> [ParseResult (MatchFiles Annex)] preferredContentParser tokens = map (parseToken tokens) . tokenizeMatcher -mkLargeFilesParser :: Annex (String -> [ParseResult (MatchFiles Annex)])-mkLargeFilesParser = do+mkMatchExpressionParser :: Annex (String -> [ParseResult (MatchFiles Annex)])+mkMatchExpressionParser = do #ifdef WITH_MAGICMIME 	magicmime <- liftIO initMagicMime 	let mimer n f = ValueToken n (usev $ f magicmime)@@ -197,26 +203,57 @@ 		] #endif 	return $ map parse . tokenizeMatcher-  where  {- Generates a matcher for files large enough (or meeting other criteria)- - to be added to the annex, rather than directly to git. -}+ - to be added to the annex, rather than directly to git.+ -+ - annex.largefiles is configured in git config, or git attributes,+ - or global git-annex config, in that order.+ -} largeFilesMatcher :: Annex GetFileMatcher-largeFilesMatcher = go =<< annexLargeFiles <$> Annex.getGitConfig+largeFilesMatcher = go =<< getGitConfigVal' annexLargeFiles   where-	go (Just expr) = do-		matcher <- mkmatcher expr+	go (HasGitConfig (Just expr)) = do+		matcher <- mkmatcher expr "git config" 		return $ const $ return matcher-	go Nothing = return $ \file -> do+	go v = return $ \file -> do 		expr <- checkAttr "annex.largefiles" file 		if null expr || expr == unspecifiedAttr-			then return matchAll-			else mkmatcher expr+			then case v of+				HasGlobalConfig (Just expr') ->+					mkmatcher expr' "git-annex config"+				_ -> return matchAll+			else mkmatcher expr "gitattributes" -	mkmatcher expr = do-		parser <- mkLargeFilesParser-		either badexpr return $ parsedToMatcher $ parser expr-	badexpr e = giveup $ "bad annex.largefiles configuration: " ++ e+	mkmatcher expr cfgfrom = do+		parser <- mkMatchExpressionParser+		either (badexpr cfgfrom) return $ parsedToMatcher $ parser expr+	badexpr cfgfrom e = giveup $ "bad annex.largefiles configuration in " ++ cfgfrom ++ ": " ++ e++newtype AddUnlockedMatcher = AddUnlockedMatcher (FileMatcher Annex)++addUnlockedMatcher :: Annex AddUnlockedMatcher+addUnlockedMatcher = AddUnlockedMatcher <$> +	(go =<< getGitConfigVal' annexAddUnlocked)+  where+	go (HasGitConfig (Just expr)) = mkmatcher expr "git config"+	go (HasGlobalConfig (Just expr)) = mkmatcher expr "git annex config"+	go _ = matchalways False++	mkmatcher :: String -> String -> Annex (FileMatcher Annex)+	mkmatcher expr cfgfrom = case Git.Config.isTrueFalse expr of+		Just b -> matchalways b+		Nothing -> do+			parser <- mkMatchExpressionParser+			either (badexpr cfgfrom) return $ parsedToMatcher $ parser expr+	badexpr cfgfrom e = giveup $ "bad annex.addunlocked configuration in " ++ cfgfrom ++ ": " ++ e++	matchalways True = return $ MOp limitAnything+	matchalways False = return $ MOp limitNothing++checkAddUnlockedMatcher :: AddUnlockedMatcher -> MatchInfo -> Annex Bool+checkAddUnlockedMatcher (AddUnlockedMatcher matcher) mi = +	checkMatcher' matcher mi S.empty  simply :: MatchFiles Annex -> ParseResult (MatchFiles Annex) simply = Right . Operation
Annex/Fixup.hs view
@@ -5,6 +5,8 @@  - Licensed under the GNU AGPL version 3 or higher.  -} +{-# LANGUAGE OverloadedStrings #-}+ module Annex.Fixup where  import Git.Types@@ -17,6 +19,7 @@ import Utility.Directory import Utility.Exception import Utility.Monad+import Utility.FileSystemEncoding import Utility.PartialPrelude  import System.IO@@ -27,6 +30,8 @@ import Control.Monad import Control.Monad.IfElse import qualified Data.Map as M+import qualified System.FilePath.ByteString as P+import qualified Data.ByteString as S import Control.Applicative import Prelude @@ -50,10 +55,10 @@ fixupDirect :: Repo -> Repo fixupDirect r@(Repo { location = l@(Local { gitdir = d, worktree = Nothing }) }) = do 	r-		{ location = l { worktree = Just (parentDir d) }+		{ location = l { worktree = Just (toRawFilePath (parentDir (fromRawFilePath d))) } 		, gitGlobalOpts = gitGlobalOpts r ++ 			[ Param "-c"-			, Param $ coreBare ++ "=" ++ boolConfig False+			, Param $ fromConfigKey coreBare ++ "=" ++ boolConfig False 			] 		} fixupDirect r = r@@ -108,12 +113,13 @@ 		, return r 		)   where-	dotgit = w </> ".git"+	dotgit = w P.</> ".git"+	dotgit' = fromRawFilePath dotgit -	replacedotgit = whenM (doesFileExist dotgit) $ do-		linktarget <- relPathDirToFile w d-		nukeFile dotgit-		createSymbolicLink linktarget dotgit+	replacedotgit = whenM (doesFileExist dotgit') $ do+		linktarget <- relPathDirToFile (fromRawFilePath w) (fromRawFilePath d)+		nukeFile dotgit'+		createSymbolicLink linktarget dotgit' 	 	unsetcoreworktree = 		maybe (error "unset core.worktree failed") (\_ -> return ())@@ -123,13 +129,13 @@ 		-- git-worktree sets up a "commondir" file that contains 		-- the path to the main git directory. 		-- Using --separate-git-dir does not.-		catchDefaultIO Nothing (headMaybe . lines <$> readFile (d </> "commondir")) >>= \case+		catchDefaultIO Nothing (headMaybe . lines <$> readFile (fromRawFilePath (d P.</> "commondir"))) >>= \case 			Just gd -> do 				-- Make the worktree's git directory 				-- contain an annex symlink to the main 				-- repository's annex directory. 				let linktarget = gd </> "annex"-				createSymbolicLink linktarget (dotgit </> "annex")+				createSymbolicLink linktarget (dotgit' </> "annex") 			Nothing -> return ()  	-- Repo adjusted, so that symlinks to objects that get checked@@ -139,12 +145,12 @@ 		| coreSymlinks c = r { location = l { gitdir = dotgit } } 		| otherwise = r -	notnoannex = isNothing <$> noAnnexFileContent (Git.repoWorkTree r)+	notnoannex = isNothing <$> noAnnexFileContent (fmap fromRawFilePath (Git.repoWorkTree r)) fixupUnusualRepos r _ = return r  needsSubmoduleFixup :: Repo -> Bool needsSubmoduleFixup (Repo { location = (Local { worktree = Just _, gitdir = d }) }) =-	(".git" </> "modules") `isInfixOf` d+	(".git" P.</> "modules") `S.isInfixOf` d needsSubmoduleFixup _ = False  needsGitLinkFixup :: Repo -> IO Bool@@ -152,6 +158,6 @@ 	-- Optimization: Avoid statting .git in the common case; only 	-- when the gitdir is not in the usual place inside the worktree 	-- might .git be a file.-	| wt </> ".git" == d = return False-	| otherwise = doesFileExist (wt </> ".git")+	| wt P.</> ".git" == d = return False+	| otherwise = doesFileExist (fromRawFilePath (wt P.</> ".git")) needsGitLinkFixup _ = return False
Annex/GitOverlay.hs view
@@ -54,7 +54,7 @@ 	(\g -> return $ g { location = modlocation (location g), gitGlobalOpts = gitGlobalOpts g ++ disableSmudgeConfig }) 	(\g g' -> g' { location = location g, gitGlobalOpts = gitGlobalOpts g })   where-	modlocation l@(Local {}) = l { worktree = Just d }+	modlocation l@(Local {}) = l { worktree = Just (toRawFilePath d) } 	modlocation _ = error "withWorkTree of non-local git repo" 	disableSmudgeConfig = map Param 		[ "-c", "filter.annex.smudge="@@ -73,7 +73,8 @@ withWorkTreeRelated d = withAltRepo modrepo unmodrepo   where 	modrepo g = liftIO $ do-		g' <- addGitEnv g "GIT_COMMON_DIR" =<< absPath (localGitDir g)+		g' <- addGitEnv g "GIT_COMMON_DIR"+			=<< absPath (fromRawFilePath (localGitDir g)) 		g'' <- addGitEnv g' "GIT_DIR" d 		return (g'' { gitEnvOverridesGitDir = True }) 	unmodrepo g g' = g'
Annex/HashObject.hs view
@@ -21,7 +21,7 @@ hashObjectHandle = maybe startup return =<< Annex.getState Annex.hashobjecthandle   where 	startup = do-		h <- inRepo $ Git.HashObject.hashObjectStart+		h <- inRepo $ Git.HashObject.hashObjectStart True 		Annex.changeState $ \s -> s { Annex.hashobjecthandle = Just h } 		return h 
Annex/Import.hs view
@@ -57,6 +57,7 @@ import qualified Data.Map.Strict as M import qualified Data.Set as S import qualified System.FilePath.Posix as Posix+import qualified System.FilePath.ByteString as P  {- Configures how to build an import tree. -} data ImportTreeConfig@@ -123,7 +124,7 @@ 			Nothing -> pure committedtree 			Just dir ->  				let subtreeref = Ref $-					fromRef committedtree ++ ":" ++ getTopFilePath dir+					fromRef committedtree ++ ":" ++ fromRawFilePath (getTopFilePath dir) 				in fromMaybe emptyTree 					<$> inRepo (Git.Ref.tree subtreeref) 		updateexportdb importedtree@@ -267,9 +268,9 @@ 		let lf = fromImportLocation loc 		let treepath = asTopFilePath lf 		let topf = asTopFilePath $-			maybe lf (\sd -> getTopFilePath sd </> lf) msubdir+			maybe lf (\sd -> getTopFilePath sd P.</> lf) msubdir 		relf <- fromRepo $ fromTopFilePath topf-		symlink <- calcRepo $ gitAnnexLink relf k+		symlink <- calcRepo $ gitAnnexLink (fromRawFilePath relf) k 		linksha <- hashSymlink symlink 		return $ TreeItem treepath (fromTreeItemType TreeSymlink) linksha @@ -327,7 +328,7 @@ 		(k:_) -> return $ Left $ Just (loc, k) 		[] -> do 			job <- liftIO $ newEmptyTMVarIO-			let ai = ActionItemOther (Just (fromImportLocation loc))+			let ai = ActionItemOther (Just (fromRawFilePath (fromImportLocation loc))) 			let downloadaction = starting ("import " ++ Remote.name remote) ai $ do 				when oldversion $ 					showNote "old version"@@ -368,9 +369,9 @@ 	 	mkkey loc tmpfile = do 		f <- fromRepo $ fromTopFilePath $ locworktreefilename loc-		backend <- chooseBackend f+		backend <- chooseBackend (fromRawFilePath f) 		let ks = KeySource-			{ keyFilename = f+			{ keyFilename = (fromRawFilePath f) 			, contentLocation = tmpfile 			, inodeCache = Nothing 			}@@ -379,7 +380,7 @@ 	locworktreefilename loc = asTopFilePath $ case importtreeconfig of 		ImportTree -> fromImportLocation loc 		ImportSubTree subdir _ ->-			getTopFilePath subdir </> fromImportLocation loc+			getTopFilePath subdir P.</> fromImportLocation loc  	getcidkey cidmap db cid = liftIO $ 		CIDDb.getContentIdentifierKeys db rs cid >>= \case@@ -450,7 +451,7 @@ wantImport matcher loc sz = checkMatcher' matcher mi mempty   where 	mi = MatchingInfo $ ProvidedInfo-		{ providedFilePath = Right $ fromImportLocation loc+		{ providedFilePath = Right $ fromRawFilePath $ fromImportLocation loc 		, providedKey = unavail "key" 		, providedFileSize = Right sz 		, providedMimeType = unavail "mime"@@ -503,4 +504,4 @@ 		, importableHistory = 			map removegitspecial (importableHistory ic) 		}-	gitspecial l = ".git" `elem` Posix.splitDirectories (fromImportLocation l)+	gitspecial l = ".git" `elem` Posix.splitDirectories (fromRawFilePath (fromImportLocation l))
Annex/Ingest.hs view
@@ -25,6 +25,7 @@  import Annex.Common import Types.KeySource+import Types.FileMatcher import Backend import Annex.Content import Annex.Perms@@ -45,6 +46,7 @@ import Git.FilePath import Annex.InodeSentinal import Annex.AdjustedBranch+import Annex.FileMatcher  import Control.Exception (IOException) @@ -92,7 +94,7 @@ 	nohardlink = withTSDelta $ liftIO . nohardlink'  	nohardlink' delta = do-		cache <- genInodeCache file delta+		cache <- genInodeCache (toRawFilePath file) delta 		return $ LockedDown cfg $ KeySource 			{ keyFilename = file 			, contentLocation = file@@ -112,7 +114,7 @@  	withhardlink' delta tmpfile = do 		createLink file tmpfile-		cache <- genInodeCache tmpfile delta+		cache <- genInodeCache (toRawFilePath tmpfile) delta 		return $ LockedDown cfg $ KeySource 			{ keyFilename = file 			, contentLocation = tmpfile@@ -136,7 +138,7 @@ 				then addLink f k mic 				else do 					mode <- liftIO $ catchMaybeIO $ fileMode <$> getFileStatus (contentLocation source)-					stagePointerFile f mode =<< hashPointerFile k+					stagePointerFile (toRawFilePath f) mode =<< hashPointerFile k 			return (Just k)  {- Ingests a locked down file into the annex. Does not update the working@@ -187,7 +189,7 @@ 	gounlocked _ _ _ = failure "failed statting file"  	success k mcache s = do-		genMetaData k (keyFilename source) s+		genMetaData k (toRawFilePath (keyFilename source)) s 		return (Just k, mcache)  	failure msg = do@@ -202,7 +204,8 @@  finishIngestUnlocked' :: Key -> KeySource -> Restage -> Annex () finishIngestUnlocked' key source restage = do-	Database.Keys.addAssociatedFile key =<< inRepo (toTopFilePath (keyFilename source))+	Database.Keys.addAssociatedFile key+		=<< inRepo (toTopFilePath (toRawFilePath (keyFilename source))) 	populateAssociatedFiles key source restage  {- Copy to any other locations using the same key. -}@@ -211,7 +214,7 @@ 	obj <- calcRepo (gitAnnexLocation key) 	g <- Annex.gitRepo 	ingestedf <- flip fromTopFilePath g-		<$> inRepo (toTopFilePath (keyFilename source))+		<$> inRepo (toTopFilePath (toRawFilePath (keyFilename source))) 	afs <- map (`fromTopFilePath` g) <$> Database.Keys.getAssociatedFiles key 	forM_ (filter (/= ingestedf) afs) $ 		populatePointerFile restage key obj@@ -226,8 +229,8 @@ cleanOldKeys :: FilePath -> Key -> Annex () cleanOldKeys file newkey = do 	g <- Annex.gitRepo-	ingestedf <- flip fromTopFilePath g <$> inRepo (toTopFilePath file)-	topf <- inRepo (toTopFilePath file)+	topf <- inRepo (toTopFilePath (toRawFilePath file))+	ingestedf <- fromRepo $ fromTopFilePath topf 	oldkeys <- filter (/= newkey) 		<$> Database.Keys.getAssociatedKey topf 	forM_ oldkeys $ \key ->@@ -243,7 +246,7 @@ 				-- so no need for any recovery. 				(f:_) -> do 					ic <- withTSDelta (liftIO . genInodeCache f)-					void $ linkToAnnex key f ic+					void $ linkToAnnex key (fromRawFilePath f) ic 				_ -> logStatus key InfoMissing  {- On error, put the file back so it doesn't seem to have vanished.@@ -254,7 +257,7 @@ 		liftIO $ nukeFile file 		-- The key could be used by other files too, so leave the 		-- content in the annex, and make a copy back to the file.-		obj <- calcRepo $ gitAnnexLocation key+		obj <- fromRawFilePath <$> calcRepo (gitAnnexLocation key) 		unlessM (liftIO $ copyFileExternal CopyTimeStamps obj file) $ 			warning $ "Unable to restore content of " ++ file ++ "; it should be located in " ++ obj 		thawContent file@@ -264,7 +267,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+	replaceFile file $ makeAnnexLink l . toRawFilePath  	-- touch symlink to have same time as the original file, 	-- as provided in the InodeCache@@ -291,7 +294,7 @@ 		Annex.Queue.addCommand "add" (ps++[Param "--"]) [file] 	, do 		l <- makeLink file key mcache-		addAnnexLink l file+		addAnnexLink l (toRawFilePath file) 	)  {- Parameters to pass to git add, forcing addition of ignored files. -}@@ -305,10 +308,10 @@  - unless symlinks are not supported. annex.addunlocked can override that.  - Also, when in an adjusted unlocked branch, always add files unlocked.  -}-addUnlocked :: Annex Bool-addUnlocked =+addUnlocked :: AddUnlockedMatcher -> MatchInfo -> Annex Bool+addUnlocked matcher mi = 	((not . coreSymlinks <$> Annex.getGitConfig) <||>-	 (annexAddUnlocked <$> Annex.getGitConfig) <||>+	 (checkAddUnlockedMatcher matcher mi) <||> 	 (maybe False isadjustedunlocked . snd <$> getCurrentBranch) 	)   where@@ -318,19 +321,20 @@  {- Adds a file to the work tree for the key, and stages it in the index.  - The content of the key may be provided in a temp file, which will be- - moved into place.+ - moved into place. If no content is provided, adds an annex link but does+ - not ingest the content.  -  - 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+addAnnexedFile :: AddUnlockedMatcher -> FilePath -> Key -> Maybe FilePath -> Annex Bool+addAnnexedFile matcher file key mtmp = ifM (addUnlocked matcher mi) 	( do 		mode <- maybe 			(pure Nothing) 			(\tmp -> liftIO $ catchMaybeIO $ fileMode <$> getFileStatus tmp) 			mtmp-		stagePointerFile file mode =<< hashPointerFile key-		Database.Keys.addAssociatedFile key =<< inRepo (toTopFilePath file)+		stagePointerFile (toRawFilePath file) mode =<< hashPointerFile key+		Database.Keys.addAssociatedFile key =<< inRepo (toTopFilePath (toRawFilePath file)) 		case mtmp of 			Just tmp -> ifM (moveAnnex key tmp) 				( linkunlocked mode >> return True@@ -347,8 +351,26 @@ 			Nothing -> return True 	)   where+	mi = case mtmp of+		Just tmp -> MatchingFile $ FileInfo+			{ currFile = toRawFilePath tmp+			, matchFile = toRawFilePath file+			}+		-- Provide as much info as we can without access to the+		-- file's content. It's better to provide wrong info+		-- than for an operation to fail just because it can't+		-- tell if a file should be unlocked or locked.+		Nothing -> MatchingInfo $ ProvidedInfo+			{ providedFilePath = Right file+			, providedKey = Right key+			, providedFileSize = Right $ fromMaybe 0 $+				keySize `fromKey` key+			, providedMimeType = Right "application/octet-stream"+			, providedMimeEncoding = Right "binary"+			}+	 	linkunlocked mode = linkFromAnnex key file mode >>= \case 		LinkAnnexFailed -> liftIO $-			writePointerFile file key mode+			writePointerFile (toRawFilePath file) key mode 		_ -> return ()-	writepointer mode = liftIO $ writePointerFile file key mode+	writepointer mode = liftIO $ writePointerFile (toRawFilePath file) key mode
Annex/Init.hs view
@@ -6,6 +6,7 @@  -}  {-# LANGUAGE CPP #-}+{-# LANGUAGE OverloadedStrings #-}  module Annex.Init ( 	ensureInitialized,@@ -22,6 +23,7 @@ import qualified Git import qualified Git.Config import qualified Git.Objects+import Git.Types (fromConfigValue) import qualified Annex.Branch import Logs.UUID import Logs.Trust.Basic@@ -54,7 +56,7 @@ import qualified Data.Map as M  checkCanInitialize :: Annex a -> Annex a-checkCanInitialize a = inRepo (noAnnexFileContent . Git.repoWorkTree) >>= \case+checkCanInitialize a = inRepo (noAnnexFileContent . fmap fromRawFilePath . Git.repoWorkTree) >>= \case 	Nothing -> a 	Just noannexmsg -> do 		warning "Initialization prevented by .noannex file (remove the file to override)"@@ -65,7 +67,9 @@ genDescription :: Maybe String -> Annex UUIDDesc genDescription (Just d) = return $ UUIDDesc $ encodeBS d genDescription Nothing = do-	reldir <- liftIO . relHome =<< liftIO . absPath =<< fromRepo Git.repoPath+	reldir <- liftIO . relHome+		=<< liftIO . absPath . fromRawFilePath+		=<< fromRepo Git.repoPath 	hostname <- fromMaybe "" <$> liftIO getHostname 	let at = if null hostname then "" else "@" 	v <- liftIO myUserName@@ -204,7 +208,7 @@ 	 - filesystem. -} 	whenM (coreSymlinks <$> Annex.getGitConfig) $ do 		warning "Disabling core.symlinks."-		setConfig (ConfigKey "core.symlinks")+		setConfig "core.symlinks" 			(Git.Config.boolConfig False)  probeLockSupport :: Annex Bool@@ -274,5 +278,5 @@  - affect it. -} propigateSecureHashesOnly :: Annex () propigateSecureHashesOnly =-	maybe noop (setConfig (ConfigKey "annex.securehashesonly"))+	maybe noop (setConfig "annex.securehashesonly" . fromConfigValue) 		=<< getGlobalConfig "annex.securehashesonly"
Annex/InodeSentinal.hs view
@@ -29,7 +29,7 @@  {- Checks if one of the provided old InodeCache matches the current  - version of a file. -}-sameInodeCache :: FilePath -> [InodeCache] -> Annex Bool+sameInodeCache :: RawFilePath -> [InodeCache] -> Annex Bool sameInodeCache _ [] = return False sameInodeCache file old = go =<< withTSDelta (liftIO . genInodeCache file)   where@@ -78,7 +78,7 @@ createInodeSentinalFile evenwithobjects =  	unlessM (alreadyexists <||> hasobjects) $ do 		s <- annexSentinalFile-		createAnnexDirectory (parentDir (sentinalFile s))+		createAnnexDirectory (parentDir (fromRawFilePath (sentinalFile s))) 		liftIO $ writeSentinalFile s   where 	alreadyexists = liftIO. sentinalFileExists =<< annexSentinalFile
Annex/Journal.hs view
@@ -20,7 +20,9 @@  import qualified Data.ByteString.Lazy as L import qualified Data.ByteString as S+import qualified System.FilePath.ByteString as P import Data.ByteString.Builder+import Data.Char  class Journalable t where 	writeJournalHandle :: Handle -> t -> IO ()@@ -44,18 +46,18 @@  - getJournalFileStale to always return a consistent journal file  - content, although possibly not the most current one.  -}-setJournalFile :: Journalable content => JournalLocked -> FilePath -> content -> Annex ()+setJournalFile :: Journalable content => JournalLocked -> RawFilePath -> content -> Annex () setJournalFile _jl file content = withOtherTmp $ \tmp -> do 	createAnnexDirectory =<< fromRepo gitAnnexJournalDir 	-- journal file is written atomically-	jfile <- fromRepo $ journalFile file+	jfile <- fromRawFilePath <$> fromRepo (journalFile file) 	let tmpfile = tmp </> takeFileName jfile 	liftIO $ do 		withFile tmpfile WriteMode $ \h -> writeJournalHandle h content 		moveFile tmpfile jfile  {- Gets any journalled content for a file in the branch. -}-getJournalFile :: JournalLocked -> FilePath -> Annex (Maybe L.ByteString)+getJournalFile :: JournalLocked -> RawFilePath -> Annex (Maybe L.ByteString) getJournalFile _jl = getJournalFileStale  {- Without locking, this is not guaranteed to be the most recent@@ -69,9 +71,9 @@  - concurrency or other issues with a lazy read, and the minor loss of  - laziness doesn't matter much, as the files are not very large.  -}-getJournalFileStale :: FilePath -> Annex (Maybe L.ByteString)+getJournalFileStale :: RawFilePath -> Annex (Maybe L.ByteString) getJournalFileStale file = inRepo $ \g -> catchMaybeIO $-	L.fromStrict <$> S.readFile (journalFile file g)+	L.fromStrict <$> S.readFile (fromRawFilePath $ journalFile file g)  {- List of existing journal files, but without locking, may miss new ones  - just being added, or may have false positives if the journal is staged@@ -81,7 +83,8 @@ 	g <- gitRepo 	fs <- liftIO $ catchDefaultIO [] $ 		getDirectoryContents $ gitAnnexJournalDir g-	return $ filter (`notElem` [".", ".."]) $ map fileJournal fs+	return $ filter (`notElem` [".", ".."]) $+		map (fromRawFilePath . fileJournal . toRawFilePath) fs  withJournalHandle :: (DirectoryHandle -> IO a) -> Annex a withJournalHandle a = do@@ -102,19 +105,33 @@  - used in the branch is not necessary, and all the files are put directly  - in the journal directory.  -}-journalFile :: FilePath -> Git.Repo -> FilePath-journalFile file repo = gitAnnexJournalDir repo </> concatMap mangle file+journalFile :: RawFilePath -> Git.Repo -> RawFilePath+journalFile file repo = gitAnnexJournalDir' repo P.</> S.concatMap mangle file   where 	mangle c-		| c == pathSeparator = "_"-		| c == '_' = "__"-		| otherwise = [c]+		| P.isPathSeparator c = S.singleton underscore+		| c == underscore = S.pack [underscore, underscore]+		| otherwise = S.singleton c+	underscore = fromIntegral (ord '_')  {- Converts a journal file (relative to the journal dir) back to the  - filename on the branch. -}-fileJournal :: FilePath -> FilePath-fileJournal = replace [pathSeparator, pathSeparator] "_" .-	replace "_" [pathSeparator]+fileJournal :: RawFilePath -> RawFilePath+fileJournal = go+  where+	go b = +		let (h, t) = S.break (== underscore) b+		in h <> case S.uncons t of+			Nothing -> t+			Just (_u, t') -> case S.uncons t' of+				Nothing -> t'			+				Just (w, t'')+					| w == underscore ->+						S.cons underscore (go t'')+					| otherwise -> +						S.cons P.pathSeparator (go t')+	+	underscore = fromIntegral (ord '_')  {- Sentinal value, only produced by lockJournal; required  - as a parameter by things that need to ensure the journal is
Annex/Link.hs view
@@ -39,11 +39,12 @@ import qualified Data.ByteString as S import qualified Data.ByteString.Char8 as S8 import qualified Data.ByteString.Lazy as L+import qualified System.FilePath.ByteString as P  type LinkTarget = String  {- Checks if a file is a link to a key. -}-isAnnexLink :: FilePath -> Annex (Maybe Key)+isAnnexLink :: RawFilePath -> Annex (Maybe Key) isAnnexLink file = maybe Nothing parseLinkTargetOrPointer <$> getAnnexLinkTarget file  {- Gets the link target of a symlink.@@ -54,13 +55,13 @@  - Returns Nothing if the file is not a symlink, or not a link to annex  - content.  -}-getAnnexLinkTarget :: FilePath -> Annex (Maybe S.ByteString)+getAnnexLinkTarget :: RawFilePath -> Annex (Maybe S.ByteString) getAnnexLinkTarget f = getAnnexLinkTarget' f 	=<< (coreSymlinks <$> Annex.getGitConfig)  {- Pass False to force looking inside file, for when git checks out  - symlinks as plain files. -}-getAnnexLinkTarget' :: FilePath -> Bool -> Annex (Maybe S.ByteString)+getAnnexLinkTarget' :: RawFilePath -> Bool -> Annex (Maybe S.ByteString) getAnnexLinkTarget' file coresymlinks = if coresymlinks 	then check probesymlink $ 		return Nothing@@ -75,9 +76,9 @@ 				| otherwise -> return Nothing 			Nothing -> fallback -	probesymlink = R.readSymbolicLink $ toRawFilePath file+	probesymlink = R.readSymbolicLink file -	probefilecontent = withFile file ReadMode $ \h -> do+	probefilecontent = withFile (fromRawFilePath file) ReadMode $ \h -> do 		s <- S.hGet h unpaddedMaxPointerSz 		-- If we got the full amount, the file is too large 		-- to be a symlink target.@@ -92,7 +93,7 @@ 					then mempty 					else s -makeAnnexLink :: LinkTarget -> FilePath -> Annex ()+makeAnnexLink :: LinkTarget -> RawFilePath -> Annex () makeAnnexLink = makeGitLink  {- Creates a link on disk.@@ -102,48 +103,48 @@  - it's staged as such, so use addAnnexLink when adding a new file or  - modified link to git.  -}-makeGitLink :: LinkTarget -> FilePath -> Annex ()+makeGitLink :: LinkTarget -> RawFilePath -> Annex () makeGitLink linktarget file = ifM (coreSymlinks <$> Annex.getGitConfig) 	( liftIO $ do-		void $ tryIO $ removeFile file-		createSymbolicLink linktarget file-	, liftIO $ writeFile file linktarget+		void $ tryIO $ removeFile (fromRawFilePath file)+		createSymbolicLink linktarget (fromRawFilePath file)+	, liftIO $ writeFile (fromRawFilePath file) linktarget 	)  {- Creates a link on disk, and additionally stages it in git. -}-addAnnexLink :: LinkTarget -> FilePath -> Annex ()+addAnnexLink :: LinkTarget -> RawFilePath -> Annex () addAnnexLink linktarget file = do 	makeAnnexLink linktarget file 	stageSymlink file =<< hashSymlink linktarget  {- Injects a symlink target into git, returning its Sha. -} hashSymlink :: LinkTarget -> Annex Sha-hashSymlink linktarget = hashBlob $ toRawFilePath $ toInternalGitPath linktarget+hashSymlink = hashBlob . toInternalGitPath . toRawFilePath  {- Stages a symlink to an annexed object, using a Sha of its target. -}-stageSymlink :: FilePath -> Sha -> Annex ()+stageSymlink :: RawFilePath -> Sha -> Annex () stageSymlink file sha = 	Annex.Queue.addUpdateIndex =<<-		inRepo (Git.UpdateIndex.stageSymlink file sha)+		inRepo (Git.UpdateIndex.stageSymlink (fromRawFilePath file) sha)  {- Injects a pointer file content into git, returning its Sha. -} hashPointerFile :: Key -> Annex Sha hashPointerFile key = hashBlob $ formatPointer key  {- Stages a pointer file, using a Sha of its content -}-stagePointerFile :: FilePath -> Maybe FileMode -> Sha -> Annex ()+stagePointerFile :: RawFilePath -> Maybe FileMode -> Sha -> Annex () stagePointerFile file mode sha = 	Annex.Queue.addUpdateIndex =<<-		inRepo (Git.UpdateIndex.stageFile sha treeitemtype file)+		inRepo (Git.UpdateIndex.stageFile sha treeitemtype $ fromRawFilePath file)   where 	treeitemtype 		| maybe False isExecutable mode = TreeExecutable 		| otherwise = TreeFile -writePointerFile :: FilePath -> Key -> Maybe FileMode -> IO ()+writePointerFile :: RawFilePath -> Key -> Maybe FileMode -> IO () writePointerFile file k mode = do-	S.writeFile file (formatPointer k)-	maybe noop (setFileMode file) mode+	S.writeFile (fromRawFilePath file) (formatPointer k)+	maybe noop (setFileMode $ fromRawFilePath file) mode  newtype Restage = Restage Bool @@ -172,14 +173,14 @@  - the worktree file is changed by something else before git update-index  - gets to look at it.  -}-restagePointerFile :: Restage -> FilePath -> InodeCache -> Annex ()+restagePointerFile :: Restage -> RawFilePath -> InodeCache -> Annex () restagePointerFile (Restage False) f _ =-	toplevelWarning True $ unableToRestage (Just f)+	toplevelWarning True $ unableToRestage $ Just $ fromRawFilePath f restagePointerFile (Restage True) f orig = withTSDelta $ \tsd -> do 	-- update-index is documented as picky about "./file" and it 	-- fails on "../../repo/path/file" when cwd is not in the repo  	-- being acted on. Avoid these problems with an absolute path.-	absf <- liftIO $ absPath f+	absf <- liftIO $ absPath $ fromRawFilePath f 	Annex.Queue.addInternalAction runner [(absf, isunmodified tsd)]   where 	isunmodified tsd = genInodeCache f tsd >>= return . \case@@ -200,7 +201,7 @@ 		    unlockindex = liftIO . maybe noop Git.LockFile.closeLock 		    showwarning = warning $ unableToRestage Nothing 		    go Nothing = showwarning-		    go (Just _) = withTmpDirIn (Git.localGitDir r) "annexindex" $ \tmpdir -> do+		    go (Just _) = withTmpDirIn (fromRawFilePath $ Git.localGitDir r) "annexindex" $ \tmpdir -> do 			let tmpindex = tmpdir </> "index" 			let updatetmpindex = do 				r' <- Git.Env.addGitEnv r Git.Index.indexEnv @@ -252,7 +253,7 @@ {- Parses a symlink target to a Key. -} parseLinkTarget :: S.ByteString -> Maybe Key parseLinkTarget l-	| isLinkToAnnex l = fileKey' $ snd $ S8.breakEnd pathsep l+	| isLinkToAnnex l = fileKey $ snd $ S8.breakEnd pathsep l 	| otherwise = Nothing   where 	pathsep '/' = True@@ -262,9 +263,9 @@ 	pathsep _ = False  formatPointer :: Key -> S.ByteString-formatPointer k = prefix <> keyFile' k <> nl+formatPointer k = prefix <> keyFile k <> nl   where-	prefix = toRawFilePath $ toInternalGitPath (pathSeparator:objectDir)+	prefix = toInternalGitPath $ P.pathSeparator `S.cons` objectDir' 	nl = S8.singleton '\n'  {- Maximum size of a file that could be a pointer to a key.@@ -283,8 +284,8 @@ {- Checks if a worktree file is a pointer to a key.  -  - Unlocked files whose content is present are not detected by this. -}-isPointerFile :: FilePath -> IO (Maybe Key)-isPointerFile f = catchDefaultIO Nothing $ withFile f ReadMode $ \h ->+isPointerFile :: RawFilePath -> IO (Maybe Key)+isPointerFile f = catchDefaultIO Nothing $ withFile (fromRawFilePath f) ReadMode $ \h -> 	parseLinkTargetOrPointer <$> S.hGet h unpaddedMaxPointerSz  {- Checks a symlink target or pointer file first line to see if it@@ -301,8 +302,7 @@ 	|| p' `S.isInfixOf` s #endif   where-	sp = (pathSeparator:objectDir)-	p = toRawFilePath sp+	p = P.pathSeparator `S.cons` objectDir' #ifdef mingw32_HOST_OS-	p' = toRawFilePath (toInternalGitPath sp)+	p' = toInternalGitPath p #endif
Annex/Locations.hs view
@@ -9,13 +9,12 @@  module Annex.Locations ( 	keyFile,-	keyFile', 	fileKey,-	fileKey', 	keyPaths, 	keyPath, 	annexDir, 	objectDir,+	objectDir', 	gitAnnexLocation, 	gitAnnexLocationDepth, 	gitAnnexLink,@@ -62,6 +61,7 @@ 	gitAnnexFeedState, 	gitAnnexMergeDir, 	gitAnnexJournalDir,+	gitAnnexJournalDir', 	gitAnnexJournalLock, 	gitAnnexGitQueueLock, 	gitAnnexPreCommitLock,@@ -93,6 +93,7 @@ import Data.Char import Data.Default import qualified Data.ByteString.Char8 as S8+import qualified System.FilePath.ByteString as P  import Common import Key@@ -104,6 +105,7 @@ import Git.FilePath import Annex.DirHashes import Annex.Fixup+import qualified Utility.RawFilePath as R  {- Conventions:  -@@ -120,24 +122,27 @@  {- The directory git annex uses for local state, relative to the .git  - directory -}-annexDir :: FilePath-annexDir = addTrailingPathSeparator "annex"+annexDir :: RawFilePath+annexDir = P.addTrailingPathSeparator "annex"  {- The directory git annex uses for locally available object content,  - relative to the .git directory -} objectDir :: FilePath-objectDir = addTrailingPathSeparator $ annexDir </> "objects"+objectDir = fromRawFilePath objectDir' +objectDir' :: RawFilePath+objectDir' = P.addTrailingPathSeparator $ annexDir P.</> "objects"+ {- Annexed file's possible locations relative to the .git directory.  - There are two different possibilities, using different hashes.  -  - Also, some repositories have a Difference in hash directory depth.  -}-annexLocations :: GitConfig -> Key -> [FilePath]+annexLocations :: GitConfig -> Key -> [RawFilePath] annexLocations config key = map (annexLocation config key) dirHashes -annexLocation :: GitConfig -> Key -> (HashLevels -> Hasher) -> FilePath-annexLocation config key hasher = objectDir </> keyPath key (hasher $ objectHashLevels config)+annexLocation :: GitConfig -> Key -> (HashLevels -> Hasher) -> RawFilePath+annexLocation config key hasher = objectDir' P.</> keyPath key (hasher $ objectHashLevels config)  {- Number of subdirectories from the gitAnnexObjectDir  - to the gitAnnexLocation. -}@@ -157,9 +162,14 @@  - This does not take direct mode into account, so in direct mode it is not  - the actual location of the file's content.  -}-gitAnnexLocation :: Key -> Git.Repo -> GitConfig -> IO FilePath-gitAnnexLocation key r config = gitAnnexLocation' key r config (annexCrippledFileSystem config) (coreSymlinks config) doesFileExist (Git.localGitDir r)-gitAnnexLocation' :: Key -> Git.Repo -> GitConfig -> Bool -> Bool -> (FilePath -> IO Bool) -> FilePath -> IO FilePath+gitAnnexLocation :: Key -> Git.Repo -> GitConfig -> IO RawFilePath+gitAnnexLocation key r config = gitAnnexLocation' key r config+	(annexCrippledFileSystem config)+	(coreSymlinks config)+	R.doesPathExist+	(Git.localGitDir r)++gitAnnexLocation' :: Key -> Git.Repo -> GitConfig -> Bool -> Bool -> (RawFilePath -> IO Bool) -> RawFilePath -> IO RawFilePath gitAnnexLocation' key r config crippled symlinkssupported checker gitdir 	{- Bare repositories default to hashDirLower for new 	 - content, as it's more portable. But check all locations. -}@@ -181,7 +191,7 @@ 	only = return . inrepo . annexLocation config key 	checkall = check $ map inrepo $ annexLocations config key -	inrepo d = gitdir </> d+	inrepo d = gitdir P.</> d 	check locs@(l:_) = fromMaybe l <$> firstM checker locs 	check [] = error "internal" @@ -192,17 +202,22 @@ 	let absfile = absNormPathUnix currdir file 	let gitdir = getgitdir currdir 	loc <- gitAnnexLocation' key r config False False (\_ -> return True) gitdir-	toInternalGitPath <$> relPathDirToFile (parentDir absfile) loc+	fromRawFilePath . toInternalGitPath . toRawFilePath+		<$> relPathDirToFile (parentDir absfile) (fromRawFilePath loc)   where 	getgitdir currdir 		{- This special case is for git submodules on filesystems not 		 - supporting symlinks; generate link target that will 		 - work portably. -} 		| not (coreSymlinks config) && needsSubmoduleFixup r =-			absNormPathUnix currdir $ Git.repoPath r </> ".git"+			toRawFilePath $+				absNormPathUnix currdir $ fromRawFilePath $+					Git.repoPath r P.</> ".git" 		| otherwise = Git.localGitDir r-	absNormPathUnix d p = toInternalGitPath $-		absPathFrom (toInternalGitPath d) (toInternalGitPath p)+	absNormPathUnix d p = fromRawFilePath $ toInternalGitPath $ toRawFilePath $+		absPathFrom+			(fromRawFilePath $ toInternalGitPath $ toRawFilePath d)+			(fromRawFilePath $ toInternalGitPath $ toRawFilePath p)  {- Calculates a symlink target as would be used in a typical git  - repository, with .git in the top of the work tree. -}@@ -211,7 +226,7 @@   where 	r' = case r of 		Git.Repo { Git.location = l@Git.Local { Git.worktree = Just wt } } ->-			r { Git.location = l { Git.gitdir = wt </> ".git" } }+			r { Git.location = l { Git.gitdir = wt P.</> ".git" } } 		_ -> r 	config' = config 		{ annexCrippledFileSystem = False@@ -222,61 +237,69 @@ gitAnnexContentLock :: Key -> Git.Repo -> GitConfig -> IO FilePath gitAnnexContentLock key r config = do 	loc <- gitAnnexLocation key r config-	return $ loc ++ ".lck"+	return $ fromRawFilePath loc ++ ".lck"  {- File that maps from a key to the file(s) in the git repository.  - Used in direct mode. -} gitAnnexMapping :: Key -> Git.Repo -> GitConfig -> IO FilePath gitAnnexMapping key r config = do 	loc <- gitAnnexLocation key r config-	return $ loc ++ ".map"+	return $ fromRawFilePath loc ++ ".map"  {- File that caches information about a key's content, used to determine  - if a file has changed.  - Used in direct mode. -} gitAnnexInodeCache :: Key -> Git.Repo -> GitConfig -> IO FilePath-gitAnnexInodeCache key r config  = do+gitAnnexInodeCache key r config = do 	loc <- gitAnnexLocation key r config-	return $ loc ++ ".cache"+	return $ fromRawFilePath loc ++ ".cache" -gitAnnexInodeSentinal :: Git.Repo -> FilePath-gitAnnexInodeSentinal r = gitAnnexDir r </> "sentinal"+gitAnnexInodeSentinal :: Git.Repo -> RawFilePath+gitAnnexInodeSentinal r = gitAnnexDir r P.</> "sentinal" -gitAnnexInodeSentinalCache :: Git.Repo -> FilePath-gitAnnexInodeSentinalCache r = gitAnnexInodeSentinal r ++ ".cache"+gitAnnexInodeSentinalCache :: Git.Repo -> RawFilePath+gitAnnexInodeSentinalCache r = gitAnnexInodeSentinal r <> ".cache"  {- The annex directory of a repository. -}-gitAnnexDir :: Git.Repo -> FilePath-gitAnnexDir r = addTrailingPathSeparator $ Git.localGitDir r </> annexDir+gitAnnexDir :: Git.Repo -> RawFilePath+gitAnnexDir r = P.addTrailingPathSeparator $ Git.localGitDir r P.</> annexDir  {- The part of the annex directory where file contents are stored. -} gitAnnexObjectDir :: Git.Repo -> FilePath-gitAnnexObjectDir r = addTrailingPathSeparator $ Git.localGitDir r </> objectDir+gitAnnexObjectDir r = fromRawFilePath $ +	P.addTrailingPathSeparator $ Git.localGitDir r P.</> objectDir'  {- .git/annex/tmp/ is used for temp files for key's contents -} gitAnnexTmpObjectDir :: Git.Repo -> FilePath-gitAnnexTmpObjectDir r = addTrailingPathSeparator $ gitAnnexDir r </> "tmp"+gitAnnexTmpObjectDir = fromRawFilePath . gitAnnexTmpObjectDir' +gitAnnexTmpObjectDir' :: Git.Repo -> RawFilePath+gitAnnexTmpObjectDir' r = P.addTrailingPathSeparator $ gitAnnexDir r P.</> "tmp"+ {- .git/annex/othertmp/ is used for other temp files -} gitAnnexTmpOtherDir :: Git.Repo -> FilePath-gitAnnexTmpOtherDir r = addTrailingPathSeparator $ gitAnnexDir r </> "othertmp"+gitAnnexTmpOtherDir r = fromRawFilePath $+	P.addTrailingPathSeparator $ gitAnnexDir r P.</> "othertmp"  {- Lock file for gitAnnexTmpOtherDir. -} gitAnnexTmpOtherLock :: Git.Repo -> FilePath-gitAnnexTmpOtherLock r = gitAnnexDir r </> "othertmp.lck"+gitAnnexTmpOtherLock r = fromRawFilePath $ gitAnnexDir r P.</> "othertmp.lck"  {- .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"+gitAnnexTmpOtherDirOld r = fromRawFilePath $ +	P.addTrailingPathSeparator $ gitAnnexDir r P.</> "misctmp"  {- .git/annex/watchtmp/ is used by the watcher and assistant -} gitAnnexTmpWatcherDir :: Git.Repo -> FilePath-gitAnnexTmpWatcherDir r = addTrailingPathSeparator $ gitAnnexDir r </> "watchtmp"+gitAnnexTmpWatcherDir r = fromRawFilePath $+	P.addTrailingPathSeparator $ gitAnnexDir r P.</> "watchtmp"  {- The temp file to use for a given key's content. -} gitAnnexTmpObjectLocation :: Key -> Git.Repo -> FilePath-gitAnnexTmpObjectLocation key r = gitAnnexTmpObjectDir r </> keyFile key+gitAnnexTmpObjectLocation key r = fromRawFilePath $+	gitAnnexTmpObjectDir' r P.</> keyFile key  {- Given a temp file such as gitAnnexTmpObjectLocation, makes a name for a  - subdirectory in the same location, that can be used as a work area@@ -293,19 +316,21 @@  {- .git/annex/bad/ is used for bad files found during fsck -} gitAnnexBadDir :: Git.Repo -> FilePath-gitAnnexBadDir r = addTrailingPathSeparator $ gitAnnexDir r </> "bad"+gitAnnexBadDir r = fromRawFilePath $+	P.addTrailingPathSeparator $ gitAnnexDir r P.</> "bad"  {- The bad file to use for a given key. -} gitAnnexBadLocation :: Key -> Git.Repo -> FilePath-gitAnnexBadLocation key r = gitAnnexBadDir r </> keyFile key+gitAnnexBadLocation key r = gitAnnexBadDir r </> fromRawFilePath (keyFile key)  {- .git/annex/foounused is used to number possibly unused keys -} gitAnnexUnusedLog :: FilePath -> Git.Repo -> FilePath-gitAnnexUnusedLog prefix r = gitAnnexDir r </> (prefix ++ "unused")+gitAnnexUnusedLog prefix r =+	fromRawFilePath (gitAnnexDir r) </> (prefix ++ "unused")  {- .git/annex/keys/ contains a database of information about keys. -} gitAnnexKeysDb :: Git.Repo -> FilePath-gitAnnexKeysDb r = gitAnnexDir r </> "keys"+gitAnnexKeysDb r = fromRawFilePath $ gitAnnexDir r P.</> "keys"  {- Lock file for the keys database. -} gitAnnexKeysDbLock :: Git.Repo -> FilePath@@ -319,7 +344,8 @@ {- .git/annex/fsck/uuid/ is used to store information about incremental  - fscks. -} gitAnnexFsckDir :: UUID -> Git.Repo -> FilePath-gitAnnexFsckDir u r = gitAnnexDir r </> "fsck" </> fromUUID u+gitAnnexFsckDir u r = fromRawFilePath $+	gitAnnexDir r P.</> "fsck" P.</> fromUUID u  {- used to store information about incremental fscks. -} gitAnnexFsckState :: UUID -> Git.Repo -> FilePath@@ -335,20 +361,21 @@  {- .git/annex/fsckresults/uuid is used to store results of git fscks -} gitAnnexFsckResultsLog :: UUID -> Git.Repo -> FilePath-gitAnnexFsckResultsLog u r = gitAnnexDir r </> "fsckresults" </> fromUUID u+gitAnnexFsckResultsLog u r = fromRawFilePath $ +	gitAnnexDir r P.</> "fsckresults" P.</> fromUUID u  {- .git/annex/smudge.log is used to log smudges worktree files that need to  - be updated. -} gitAnnexSmudgeLog :: Git.Repo -> FilePath-gitAnnexSmudgeLog r = gitAnnexDir r </> "smudge.log"+gitAnnexSmudgeLog r = fromRawFilePath $ gitAnnexDir r P.</> "smudge.log"  gitAnnexSmudgeLock :: Git.Repo -> FilePath-gitAnnexSmudgeLock r = gitAnnexDir r </> "smudge.lck"+gitAnnexSmudgeLock r = fromRawFilePath $ gitAnnexDir r P.</> "smudge.lck"  {- .git/annex/export/uuid/ is used to store information about  - exports to special remotes. -} gitAnnexExportDir :: UUID -> Git.Repo -> FilePath-gitAnnexExportDir u r = gitAnnexDir r </> "export" </> fromUUID u+gitAnnexExportDir u r = fromRawFilePath (gitAnnexDir r) </> "export" </> fromUUID u  {- Directory containing database used to record export info. -} gitAnnexExportDbDir :: UUID -> Git.Repo -> FilePath@@ -365,7 +392,8 @@ {- Log file used to keep track of files that were in the tree exported to a  - remote, but were excluded by its preferred content settings. -} gitAnnexExportExcludeLog :: UUID -> Git.Repo -> FilePath-gitAnnexExportExcludeLog u r = gitAnnexDir r </> "export.ex" </> fromUUID u+gitAnnexExportExcludeLog u r = fromRawFilePath $+	gitAnnexDir r P.</> "export.ex" P.</> fromUUID u  {- Directory containing database used to record remote content ids.  -@@ -373,7 +401,7 @@  - need to be rebuilt with a new name.)  -} gitAnnexContentIdentifierDbDir :: Git.Repo -> FilePath-gitAnnexContentIdentifierDbDir r = gitAnnexDir r </> "cids"+gitAnnexContentIdentifierDbDir r = fromRawFilePath $ gitAnnexDir r P.</> "cids"  {- Lock file for writing to the content id database. -} gitAnnexContentIdentifierLock :: Git.Repo -> FilePath@@ -382,125 +410,137 @@ {- .git/annex/schedulestate is used to store information about when  - scheduled jobs were last run. -} gitAnnexScheduleState :: Git.Repo -> FilePath-gitAnnexScheduleState r = gitAnnexDir r </> "schedulestate"+gitAnnexScheduleState r = fromRawFilePath $ gitAnnexDir r P.</> "schedulestate"  {- .git/annex/creds/ is used to store credentials to access some special  - remotes. -} gitAnnexCredsDir :: Git.Repo -> FilePath-gitAnnexCredsDir r = addTrailingPathSeparator $ gitAnnexDir r </> "creds"+gitAnnexCredsDir r = fromRawFilePath $+	P.addTrailingPathSeparator $ gitAnnexDir r P.</> "creds"  {- .git/annex/certificate.pem and .git/annex/key.pem are used by the webapp  - when HTTPS is enabled -} gitAnnexWebCertificate :: Git.Repo -> FilePath-gitAnnexWebCertificate r = gitAnnexDir r </> "certificate.pem"+gitAnnexWebCertificate r = fromRawFilePath $ gitAnnexDir r P.</> "certificate.pem" gitAnnexWebPrivKey :: Git.Repo -> FilePath-gitAnnexWebPrivKey r = gitAnnexDir r </> "privkey.pem"+gitAnnexWebPrivKey r = fromRawFilePath $ gitAnnexDir r P.</> "privkey.pem"  {- .git/annex/feeds/ is used to record per-key (url) state by importfeeds -} gitAnnexFeedStateDir :: Git.Repo -> FilePath-gitAnnexFeedStateDir r = addTrailingPathSeparator $ gitAnnexDir r </> "feedstate"+gitAnnexFeedStateDir r = fromRawFilePath $+	P.addTrailingPathSeparator $ gitAnnexDir r P.</> "feedstate"  gitAnnexFeedState :: Key -> Git.Repo -> FilePath-gitAnnexFeedState k r = gitAnnexFeedStateDir r </> keyFile k+gitAnnexFeedState k r = gitAnnexFeedStateDir r </> fromRawFilePath (keyFile k)  {- .git/annex/merge/ is used as a empty work tree for direct mode merges and  - merges in adjusted branches. -} gitAnnexMergeDir :: Git.Repo -> FilePath-gitAnnexMergeDir r = addTrailingPathSeparator $ gitAnnexDir r </> "merge"+gitAnnexMergeDir r = fromRawFilePath $+	P.addTrailingPathSeparator $ gitAnnexDir r P.</> "merge"  {- .git/annex/transfer/ is used to record keys currently  - being transferred, and other transfer bookkeeping info. -} gitAnnexTransferDir :: Git.Repo -> FilePath-gitAnnexTransferDir r = addTrailingPathSeparator $ gitAnnexDir r </> "transfer"+gitAnnexTransferDir r = fromRawFilePath $+	P.addTrailingPathSeparator $ gitAnnexDir r P.</> "transfer"  {- .git/annex/journal/ is used to journal changes made to the git-annex  - branch -} gitAnnexJournalDir :: Git.Repo -> FilePath-gitAnnexJournalDir r = addTrailingPathSeparator $ gitAnnexDir r </> "journal"+gitAnnexJournalDir r = fromRawFilePath $+	P.addTrailingPathSeparator $ gitAnnexDir r P.</> "journal" +gitAnnexJournalDir' :: Git.Repo -> RawFilePath+gitAnnexJournalDir' r = P.addTrailingPathSeparator $ gitAnnexDir r P.</> "journal"+ {- Lock file for the journal. -} gitAnnexJournalLock :: Git.Repo -> FilePath-gitAnnexJournalLock r = gitAnnexDir r </> "journal.lck"+gitAnnexJournalLock r = fromRawFilePath $ gitAnnexDir r P.</> "journal.lck"  {- Lock file for flushing a git queue that writes to the git index or  - other git state that should only have one writer at a time. -} gitAnnexGitQueueLock :: Git.Repo -> FilePath-gitAnnexGitQueueLock r = gitAnnexDir r </> "gitqueue.lck"+gitAnnexGitQueueLock r = fromRawFilePath $ gitAnnexDir r P.</> "gitqueue.lck"  {- Lock file for the pre-commit hook. -} gitAnnexPreCommitLock :: Git.Repo -> FilePath-gitAnnexPreCommitLock r = gitAnnexDir r </> "precommit.lck"+gitAnnexPreCommitLock r = fromRawFilePath $ gitAnnexDir r P.</> "precommit.lck"  {- Lock file for direct mode merge. -} gitAnnexMergeLock :: Git.Repo -> FilePath-gitAnnexMergeLock r = gitAnnexDir r </> "merge.lck"+gitAnnexMergeLock r = fromRawFilePath $ gitAnnexDir r P.</> "merge.lck"  {- .git/annex/index is used to stage changes to the git-annex branch -} gitAnnexIndex :: Git.Repo -> FilePath-gitAnnexIndex r = gitAnnexDir r </> "index"+gitAnnexIndex r = fromRawFilePath $ gitAnnexDir r P.</> "index"  {- Holds the ref of the git-annex branch that the index was last updated to.  -  - The .lck in the name is a historical accident; this is not used as a  - lock. -} gitAnnexIndexStatus :: Git.Repo -> FilePath-gitAnnexIndexStatus r = gitAnnexDir r </> "index.lck"+gitAnnexIndexStatus r = fromRawFilePath $ gitAnnexDir r P.</> "index.lck"  {- The index file used to generate a filtered branch view._-} gitAnnexViewIndex :: Git.Repo -> FilePath-gitAnnexViewIndex r = gitAnnexDir r </> "viewindex"+gitAnnexViewIndex r = fromRawFilePath $ gitAnnexDir r P.</> "viewindex"  {- File containing a log of recently accessed views. -} gitAnnexViewLog :: Git.Repo -> FilePath-gitAnnexViewLog r = gitAnnexDir r </> "viewlog"+gitAnnexViewLog r = fromRawFilePath $ gitAnnexDir r P.</> "viewlog"  {- List of refs that have already been merged into the git-annex branch. -} gitAnnexMergedRefs :: Git.Repo -> FilePath-gitAnnexMergedRefs r = gitAnnexDir r </> "mergedrefs"+gitAnnexMergedRefs r = fromRawFilePath $ gitAnnexDir r P.</> "mergedrefs"  {- List of refs that should not be merged into the git-annex branch. -} gitAnnexIgnoredRefs :: Git.Repo -> FilePath-gitAnnexIgnoredRefs r = gitAnnexDir r </> "ignoredrefs"+gitAnnexIgnoredRefs r = fromRawFilePath $ gitAnnexDir r P.</> "ignoredrefs"  {- Pid file for daemon mode. -} gitAnnexPidFile :: Git.Repo -> FilePath-gitAnnexPidFile r = gitAnnexDir r </> "daemon.pid"+gitAnnexPidFile r = fromRawFilePath $ gitAnnexDir r P.</> "daemon.pid"  {- Pid lock file for pidlock mode -} gitAnnexPidLockFile :: Git.Repo -> FilePath-gitAnnexPidLockFile r = gitAnnexDir r </> "pidlock"+gitAnnexPidLockFile r = fromRawFilePath $ gitAnnexDir r P.</> "pidlock"  {- Status file for daemon mode. -} gitAnnexDaemonStatusFile :: Git.Repo -> FilePath-gitAnnexDaemonStatusFile r = gitAnnexDir r </> "daemon.status"+gitAnnexDaemonStatusFile r = fromRawFilePath $+	gitAnnexDir r P.</> "daemon.status"  {- Log file for daemon mode. -} gitAnnexLogFile :: Git.Repo -> FilePath-gitAnnexLogFile r = gitAnnexDir r </> "daemon.log"+gitAnnexLogFile r = fromRawFilePath $ gitAnnexDir r P.</> "daemon.log"  {- Log file for fuzz test. -} gitAnnexFuzzTestLogFile :: Git.Repo -> FilePath-gitAnnexFuzzTestLogFile r = gitAnnexDir r </> "fuzztest.log"+gitAnnexFuzzTestLogFile r = fromRawFilePath $+	gitAnnexDir r P.</> "fuzztest.log"  {- Html shim file used to launch the webapp. -} gitAnnexHtmlShim :: Git.Repo -> FilePath-gitAnnexHtmlShim r = gitAnnexDir r </> "webapp.html"+gitAnnexHtmlShim r = fromRawFilePath $ gitAnnexDir r P.</> "webapp.html"  {- File containing the url to the webapp. -} gitAnnexUrlFile :: Git.Repo -> FilePath-gitAnnexUrlFile r = gitAnnexDir r </> "url"+gitAnnexUrlFile r = fromRawFilePath $ gitAnnexDir r P.</> "url"  {- Temporary file used to edit configuriation from the git-annex branch. -} gitAnnexTmpCfgFile :: Git.Repo -> FilePath-gitAnnexTmpCfgFile r = gitAnnexDir r </> "config.tmp"+gitAnnexTmpCfgFile r = fromRawFilePath $ gitAnnexDir r P.</> "config.tmp"  {- .git/annex/ssh/ is used for ssh connection caching -} gitAnnexSshDir :: Git.Repo -> FilePath-gitAnnexSshDir r = addTrailingPathSeparator $ gitAnnexDir r </> "ssh"+gitAnnexSshDir r = fromRawFilePath $+	P.addTrailingPathSeparator $ gitAnnexDir r P.</> "ssh"  {- .git/annex/remotes/ is used for remote-specific state. -} gitAnnexRemotesDir :: Git.Repo -> FilePath-gitAnnexRemotesDir r = addTrailingPathSeparator $ gitAnnexDir r </> "remotes"+gitAnnexRemotesDir r = fromRawFilePath $+	P.addTrailingPathSeparator $ gitAnnexDir r P.</> "remotes"  {- This is the base directory name used by the assistant when making  - repositories, by default. -}@@ -557,11 +597,8 @@  - Changing what this function escapes and how is not a good idea, as it  - can cause existing objects to get lost.  -}-keyFile :: Key -> FilePath-keyFile = fromRawFilePath . keyFile'--keyFile' :: Key -> RawFilePath-keyFile' k = +keyFile :: Key -> RawFilePath+keyFile k =  	let b = serializeKey' k 	in if S8.any (`elem` ['&', '%', ':', '/']) b 		then S8.concatMap esc b@@ -576,11 +613,8 @@  {- Reverses keyFile, converting a filename fragment (ie, the basename of  - the symlink target) into a key. -}-fileKey :: FilePath -> Maybe Key-fileKey = fileKey' . toRawFilePath--fileKey' :: RawFilePath -> Maybe Key-fileKey' = deserializeKey' . S8.intercalate "/" . map go . S8.split '%'+fileKey :: RawFilePath -> Maybe Key+fileKey = deserializeKey' . S8.intercalate "/" . map go . S8.split '%'   where 	go = S8.concat . unescafterfirst . S8.split '&' 	unescafterfirst [] = []@@ -599,8 +633,8 @@  - The file is put in a directory with the same name, this allows  - write-protecting the directory to avoid accidental deletion of the file.  -}-keyPath :: Key -> Hasher -> FilePath-keyPath key hasher = hasher key </> f </> f+keyPath :: Key -> Hasher -> RawFilePath+keyPath key hasher = hasher key P.</> f P.</> f   where 	f = keyFile key @@ -610,5 +644,5 @@  - This is compatible with the annexLocations, for interoperability between  - special remotes and git-annex repos.  -}-keyPaths :: Key -> [FilePath]+keyPaths :: Key -> [RawFilePath] keyPaths key = map (\h -> keyPath key (h def)) dirHashes
Annex/MetaData.hs view
@@ -37,7 +37,7 @@  -  - Also, can generate new metadata, if configured to do so.  -}-genMetaData :: Key -> FilePath -> FileStatus -> Annex ()+genMetaData :: Key -> RawFilePath -> FileStatus -> Annex () genMetaData key file status = do 	catKeyFileHEAD file >>= \case 		Nothing -> noop@@ -53,8 +53,8 @@   where 	mtime = posixSecondsToUTCTime $ realToFrac $ modificationTime status 	warncopied = warning $ -		"Copied metadata from old version of " ++ file ++ " to new version. " ++ -		"If you don't want this copied metadata, run: git annex metadata --remove-all " ++ file+		"Copied metadata from old version of " ++ fromRawFilePath file ++ " to new version. " ++ +		"If you don't want this copied metadata, run: git annex metadata --remove-all " ++ fromRawFilePath file 	-- If the only fields copied were date metadata, and they'll 	-- be overwritten with the current mtime, no need to warn about 	-- copying.
Annex/Notification.hs view
@@ -60,7 +60,7 @@ 	wanted <- Annex.getState Annex.desktopnotify 	when (notifyFinish wanted) $ liftIO $ do 		client <- DBus.Client.connectSession-		void $ Notify.notify client (droppedNote ok f)+		void $ Notify.notify client (droppedNote ok (fromRawFilePath f)) #else notifyDrop (AssociatedFile (Just _)) _ = noop #endif
Annex/NumCopies.hs view
@@ -72,7 +72,7 @@  getAssociatedFileNumCopies :: AssociatedFile -> Annex NumCopies getAssociatedFileNumCopies (AssociatedFile afile) =-	maybe getNumCopies getFileNumCopies afile+	maybe getNumCopies getFileNumCopies (fromRawFilePath <$> afile)  {- This is the globally visible numcopies value for a file. So it does  - not include local configuration in the git config or command line
Annex/Perms.hs view
@@ -70,7 +70,7 @@ createAnnexDirectory :: FilePath -> Annex () createAnnexDirectory dir = walk dir [] =<< top   where-	top = parentDir <$> fromRepo gitAnnexDir+	top = parentDir . fromRawFilePath <$> fromRepo gitAnnexDir 	walk d below stop 		| d `equalFilePath` stop = done 		| otherwise = ifM (liftIO $ doesDirectoryExist d)
Annex/SpecialRemote.hs view
@@ -5,6 +5,8 @@  - Licensed under the GNU AGPL version 3 or higher.  -} +{-# LANGUAGE OverloadedStrings #-}+ module Annex.SpecialRemote ( 	module Annex.SpecialRemote, 	module Annex.SpecialRemote.Config@@ -92,7 +94,7 @@ 			_ -> return ()   where 	configured rc = fromMaybe False $-		Git.Config.isTrue =<< M.lookup autoEnableField rc+		Git.Config.isTrueFalse =<< M.lookup autoEnableField rc 	canenable u = (/= DeadTrusted) <$> lookupTrust u 	getenabledremotes = M.fromList 		. map (\r -> (getcu r, r))
Annex/Ssh.hs view
@@ -43,6 +43,7 @@ #endif  import Control.Concurrent.STM+import qualified Data.ByteString as S  {- Some ssh commands are fed stdin on a pipe and so should be allowed to  - consume it. But ssh commands that are not piped stdin should generally@@ -325,7 +326,7 @@ {- Note that this looks at the true length of the path in bytes, as it will  - appear on disk. -} valid_unix_socket_path :: FilePath -> Bool-valid_unix_socket_path f = length (decodeW8 f) < sizeof_sockaddr_un_sun_path+valid_unix_socket_path f = S.length (encodeBS f) < sizeof_sockaddr_un_sun_path  {- Parses the SSH port, and returns the other OpenSSH options. If  - several ports are found, the last one takes precedence. -}
Annex/UUID.hs view
@@ -11,7 +11,10 @@  - Licensed under the GNU AGPL version 3 or higher.  -} +{-# LANGUAGE OverloadedStrings #-}+ module Annex.UUID (+	configkeyUUID, 	getUUID, 	getRepoUUID, 	getUncachedUUID,@@ -32,6 +35,7 @@ import qualified Annex import qualified Git import qualified Git.Config+import Git.Types import Config  import qualified Data.UUID as U@@ -39,8 +43,8 @@ import qualified Data.UUID.V5 as U5 import Data.String -configkey :: ConfigKey-configkey = annexConfig "uuid"+configkeyUUID :: ConfigKey+configkeyUUID = annexConfig "uuid"  {- Generates a random UUID, that does not include the MAC address. -} genUUID :: IO UUID@@ -81,20 +85,16 @@  removeRepoUUID :: Annex () removeRepoUUID = do-	unsetConfig configkey+	unsetConfig configkeyUUID 	storeUUID NoUUID  getUncachedUUID :: Git.Repo -> UUID-getUncachedUUID = toUUID . Git.Config.get key ""-  where-	(ConfigKey key) = configkey+getUncachedUUID = toUUID . Git.Config.get configkeyUUID ""  -- Does the repo's config have a key for the UUID? -- True even when the key has no value. isUUIDConfigured :: Git.Repo -> Bool-isUUIDConfigured = isJust . Git.Config.getMaybe key -  where-	(ConfigKey key) = configkey+isUUIDConfigured = isJust . Git.Config.getMaybe configkeyUUID  {- Make sure that the repo has an annex.uuid setting. -} prepUUID :: Annex ()@@ -104,7 +104,7 @@ storeUUID :: UUID -> Annex () storeUUID u = do 	Annex.changeGitConfig $ \c -> c { annexUUID = u }-	storeUUIDIn configkey u+	storeUUIDIn configkeyUUID u  storeUUIDIn :: ConfigKey -> UUID -> Annex () storeUUIDIn configfield = setConfig configfield . fromUUID@@ -112,7 +112,7 @@ {- Only sets the configkey in the Repo; does not change .git/config -} setUUID :: Git.Repo -> UUID -> IO Git.Repo setUUID r u = do-	let s = show configkey ++ "=" ++ fromUUID u+	let s = encodeBS' $ show configkeyUUID ++ "=" ++ fromUUID u 	Git.Config.store s r  -- Dummy uuid for the whole web. Do not alter.
Annex/VariantFile.hs view
@@ -36,7 +36,7 @@  -} variantFile :: FilePath -> Key -> FilePath variantFile file key-	| doubleconflict = mkVariant file (keyFile key)+	| doubleconflict = mkVariant file (fromRawFilePath (keyFile key)) 	| otherwise = mkVariant file (shortHash $ serializeKey' key)   where 	doubleconflict = variantMarker `isInfixOf` file
Annex/Version.hs view
@@ -6,11 +6,13 @@  -}  {-# LANGUAGE CPP #-}+{-# LANGUAGE OverloadedStrings #-}  module Annex.Version where  import Annex.Common import Config+import Git.Types import Types.RepoVersion import qualified Annex 
Annex/View.hs view
@@ -5,6 +5,8 @@  - Licensed under the GNU AGPL version 3 or higher.  -} +{-# LANGUAGE OverloadedStrings #-}+ module Annex.View where  import Annex.Common@@ -80,7 +82,7 @@ 			)   where 	mkFilterValues v-		| any (`elem` v) "*?" = FilterGlob v+		| any (`elem` v) ['*', '?'] = FilterGlob v 		| otherwise = FilterValues $ S.singleton $ toMetaValue $ encodeBS v 	mkExcludeValues = ExcludeValues . S.singleton . toMetaValue . encodeBS @@ -358,13 +360,14 @@  	go uh topf _sha _mode (Just k) = do 		metadata <- getCurrentMetaData k-		let f = getTopFilePath topf+		let f = fromRawFilePath $ getTopFilePath topf 		let metadata' = getfilemetadata f `unionMetaData` metadata 		forM_ (genviewedfiles f metadata') $ \fv -> do-			f' <- fromRepo $ fromTopFilePath $ asTopFilePath fv+			f' <- fromRawFilePath <$> +				fromRepo (fromTopFilePath $ asTopFilePath $ toRawFilePath fv) 			stagesymlink uh f' =<< calcRepo (gitAnnexLink f' k) 	go uh topf (Just sha) (Just treeitemtype) Nothing-		| "." `isPrefixOf` getTopFilePath topf =+		| "." `B.isPrefixOf` getTopFilePath topf = 			liftIO $ Git.UpdateIndex.streamUpdateIndex' uh $ 				pureStreamer $ updateIndexLine sha treeitemtype topf 	go _ _ _ _  _ = noop@@ -403,7 +406,7 @@ 				=<< catKey (DiffTree.dstsha item) 		| otherwise = noop 	handlechange item a = maybe noop-		(void . commandAction . a (getTopFilePath $ DiffTree.file item))+		(void . commandAction . a (fromRawFilePath $ getTopFilePath $ DiffTree.file item))  {- Runs an action using the view index file.  - Note that the file does not necessarily exist, or can contain
Annex/WorkTree.hs view
@@ -23,6 +23,7 @@ import qualified Database.Keys import qualified Database.Keys.SQL import Config+import qualified Utility.RawFilePath as R  {- Looks up the key corresponding to an annexed file in the work tree,  - by examining what the file links to.@@ -33,35 +34,35 @@  - When in an adjusted branch that may have hidden the file, looks for a  - pointer to a key in the original branch.  -}-lookupFile :: FilePath -> Annex (Maybe Key)+lookupFile :: RawFilePath -> Annex (Maybe Key) lookupFile = lookupFile' catkeyfile   where 	catkeyfile file =-		ifM (liftIO $ doesFileExist file)+		ifM (liftIO $ doesFileExist $ fromRawFilePath file) 			( catKeyFile file 			, catKeyFileHidden file =<< getCurrentBranch 			) -lookupFileNotHidden :: FilePath -> Annex (Maybe Key)+lookupFileNotHidden :: RawFilePath -> Annex (Maybe Key) lookupFileNotHidden = lookupFile' catkeyfile   where 	catkeyfile file =-		ifM (liftIO $ doesFileExist file)+		ifM (liftIO $ doesFileExist $ fromRawFilePath file) 			( catKeyFile file 			, return Nothing 			) -lookupFile' :: (FilePath -> Annex (Maybe Key)) -> FilePath -> Annex (Maybe Key)+lookupFile' :: (RawFilePath -> Annex (Maybe Key)) -> RawFilePath -> Annex (Maybe Key) lookupFile' catkeyfile file = isAnnexLink file >>= \case 	Just key -> return (Just key) 	Nothing -> catkeyfile file  {- Modifies an action to only act on files that are already annexed,  - and passes the key on to it. -}-whenAnnexed :: (FilePath -> Key -> Annex (Maybe a)) -> FilePath -> Annex (Maybe a)+whenAnnexed :: (RawFilePath -> Key -> Annex (Maybe a)) -> RawFilePath -> Annex (Maybe a) whenAnnexed a file = ifAnnexed file (a file) (return Nothing) -ifAnnexed :: FilePath -> (Key -> Annex a) -> Annex a -> Annex a+ifAnnexed :: RawFilePath -> (Key -> Annex a) -> Annex a -> Annex a ifAnnexed file yes no = maybe no yes =<< lookupFile file  {- Find all unlocked files and update the keys database for them. @@ -98,14 +99,16 @@ 			f <- fromRepo $ fromTopFilePath tf 			liftIO (isPointerFile f) >>= \case 				Just k' | k' == k -> do-					destmode <- liftIO $ catchMaybeIO $ fileMode <$> getFileStatus f-					ic <- replaceFile f $ \tmp ->+					destmode <- liftIO $ catchMaybeIO $+						fileMode <$> R.getFileStatus f+					ic <- replaceFile (fromRawFilePath f) $ \tmp -> do+						let tmp' = toRawFilePath tmp 						linkFromAnnex k tmp destmode >>= \case 							LinkAnnexOk -> -								withTSDelta (liftIO . genInodeCache tmp)+								withTSDelta (liftIO . genInodeCache tmp') 							LinkAnnexNoop -> return Nothing 							LinkAnnexFailed -> liftIO $ do-								writePointerFile tmp k destmode+								writePointerFile tmp' k destmode 								return Nothing 					maybe noop (restagePointerFile (Restage True) f) ic 				_ -> noop
Assistant/MakeRemote.hs view
@@ -5,6 +5,8 @@  - Licensed under the GNU AGPL version 3 or higher.  -} +{-# LANGUAGE OverloadedStrings #-}+ module Assistant.MakeRemote where  import Assistant.Common
Assistant/MakeRepo.hs view
@@ -5,6 +5,8 @@  - Licensed under the GNU AGPL version 3 or higher.  -} +{-# LANGUAGE OverloadedStrings #-}+ module Assistant.MakeRepo where  import Assistant.WebApp.Common
Assistant/Repair.hs view
@@ -91,7 +91,7 @@ 	remoterepair fsckresults = case Remote.repairRepo =<< mrmt of 		Nothing -> return False 		Just mkrepair -> do-			thisrepopath <- liftIO . absPath+			thisrepopath <- liftIO . absPath . fromRawFilePath 				=<< liftAnnex (fromRepo Git.repoPath) 			a <- liftAnnex $ mkrepair $ 				repair fsckresults (Just thisrepopath)@@ -130,7 +130,7 @@ 	repairStaleLocks lockfiles 	return $ not $ null lockfiles   where-	findgitfiles = dirContentsRecursiveSkipping (== dropTrailingPathSeparator annexDir) True . Git.localGitDir+	findgitfiles = dirContentsRecursiveSkipping (== dropTrailingPathSeparator (fromRawFilePath annexDir)) True . fromRawFilePath . Git.localGitDir 	islock f 		| "gc.pid" `isInfixOf` f = False 		| ".lock" `isSuffixOf` f = True
Assistant/Sync.hs view
@@ -5,6 +5,8 @@  - Licensed under the GNU AGPL version 3 or higher.  -} +{-# LANGUAGE OverloadedStrings #-}+ module Assistant.Sync where  import Assistant.Common
Assistant/Threads/Committer.hs view
@@ -286,7 +286,7 @@ 	  	ks = keySource ld 		doadd = sanitycheck ks $ do 			(mkey, _mcache) <- liftAnnex $ do-				showStart "add" $ keyFilename ks+				showStart "add" $ toRawFilePath $ keyFilename ks 				ingest nullMeterUpdate (Just $ LockedDown lockdownconfig ks) Nothing 			maybe (failedingest change) (done change $ keyFilename ks) mkey 	add _ _ = return Nothing@@ -308,7 +308,7 @@ 		if M.null m 			then forM toadd (add cfg) 			else forM toadd $ \c -> do-				mcache <- liftIO $ genInodeCache (changeFile c) delta+				mcache <- liftIO $ genInodeCache (toRawFilePath (changeFile c)) delta 				case mcache of 					Nothing -> add cfg c 					Just cache ->@@ -325,7 +325,7 @@ 	removedKeysMap :: InodeComparisonType -> [Change] -> Annex (M.Map InodeCacheKey Key) 	removedKeysMap ct l = do 		mks <- forM (filter isRmChange l) $ \c ->-			catKeyFile $ changeFile c+			catKeyFile $ toRawFilePath $ changeFile c 		M.fromList . concat <$> mapM mkpairs (catMaybes mks) 	  where 		mkpairs k = map (\c -> (inodeCacheToKey ct c, k)) <$>@@ -339,7 +339,7 @@ 	done change file key = liftAnnex $ do 		logStatus key InfoPresent 		mode <- liftIO $ catchMaybeIO $ fileMode <$> getFileStatus file-		stagePointerFile file mode =<< hashPointerFile key+		stagePointerFile (toRawFilePath file) mode =<< hashPointerFile key 		showEndOk 		return $ Just $ finishedChange change key @@ -457,5 +457,5 @@ 			handleDrops "file renamed" present k af []   where 	f = changeFile change-	af = AssociatedFile (Just f)+	af = AssociatedFile (Just (toRawFilePath f)) checkChangeContent _ = noop
Assistant/Threads/ConfigMonitor.hs view
@@ -44,7 +44,8 @@ 		when (old /= new) $ do 			let changedconfigs = new `S.difference` old 			debug $ "reloading config" : -				map fst (S.toList changedconfigs)+				map (fromRawFilePath . fst)+				(S.toList changedconfigs) 			reloadConfigs new 			{- Record a commit to get this config 			 - change pushed out to remotes. -}@@ -53,10 +54,10 @@ 		loop new  {- Config files, and their checksums. -}-type Configs = S.Set (FilePath, Sha)+type Configs = S.Set (RawFilePath, Sha)  {- All git-annex's config files, and actions to run when they change. -}-configFilesActions :: [(FilePath, Assistant ())]+configFilesActions :: [(RawFilePath, Assistant ())] configFilesActions = 	[ (uuidLog, void $ liftAnnex uuidDescMapLoad) 	, (remoteLog, void $ liftAnnex remoteListRefresh)@@ -89,5 +90,5 @@ getConfigs = S.fromList . map extract 	<$> liftAnnex (inRepo $ LsTree.lsTreeFiles Annex.Branch.fullname files)   where-	files = map fst configFilesActions+	files = map (fromRawFilePath . fst) configFilesActions 	extract treeitem = (getTopFilePath $ LsTree.file treeitem, LsTree.sha treeitem)
Assistant/Threads/Merger.hs view
@@ -26,7 +26,7 @@ mergeThread :: NamedThread mergeThread = namedThread "Merger" $ do 	g <- liftAnnex gitRepo-	let dir = Git.localGitDir g </> "refs"+	let dir = fromRawFilePath (Git.localGitDir g) </> "refs" 	liftIO $ createDirectoryIfMissing True dir 	let hook a = Just <$> asIO2 (runHandler a) 	changehook <- hook onChange
Assistant/Threads/MountWatcher.hs view
@@ -159,7 +159,7 @@  -} remotesUnder :: FilePath -> Assistant [Remote] remotesUnder dir = do-	repotop <- liftAnnex $ fromRepo Git.repoPath+	repotop <- liftAnnex $ fromRawFilePath <$> fromRepo Git.repoPath 	rs <- liftAnnex remoteList 	pairs <- liftAnnex $ mapM (checkremote repotop) rs 	let (waschanged, rs') = unzip pairs
Assistant/Threads/PairListener.hs view
@@ -119,7 +119,7 @@ pairAckReceived :: Bool -> Maybe PairingInProgress -> PairMsg -> [PairingInProgress] -> Assistant [PairingInProgress] pairAckReceived True (Just pip) msg cache = do 	stopSending pip-	repodir <- repoPath <$> liftAnnex gitRepo+	repodir <- fromRawFilePath . repoPath <$> liftAnnex gitRepo 	liftIO $ setupAuthorizedKeys msg repodir 	finishedLocalPairing msg (inProgressSshKeyPair pip) 	startSending pip PairDone $ multicastPairMsg
Assistant/Threads/SanityChecker.hs view
@@ -155,10 +155,11 @@ 	(unstaged, cleanup) <- liftIO $ Git.LsFiles.notInRepo False ["."] g 	now <- liftIO getPOSIXTime 	forM_ unstaged $ \file -> do-		ms <- liftIO $ catchMaybeIO $ getSymbolicLinkStatus file+		let file' = fromRawFilePath file+		ms <- liftIO $ catchMaybeIO $ getSymbolicLinkStatus file' 		case ms of 			Just s	| toonew (statusChangeTime s) now -> noop-				| isSymbolicLink s -> addsymlink file ms+				| isSymbolicLink s -> addsymlink file' ms 			_ -> noop 	liftIO $ void cleanup @@ -268,5 +269,5 @@ checkRepoExists :: Assistant () checkRepoExists = do 	g <- liftAnnex gitRepo-	liftIO $ unlessM (doesDirectoryExist $ Git.repoPath g) $+	liftIO $ unlessM (doesDirectoryExist $ fromRawFilePath $ Git.repoPath g) $ 		terminateSelf
Assistant/Threads/Watcher.hs view
@@ -138,8 +138,9 @@ 		top <- liftAnnex $ fromRepo Git.repoPath 		(fs, cleanup) <- liftAnnex $ inRepo $ LsFiles.deleted [top] 		forM_ fs $ \f -> do-			liftAnnex $ onDel' f-			maybe noop recordChange =<< madeChange f RmChange+			let f' = fromRawFilePath f+			liftAnnex $ onDel' f'+			maybe noop recordChange =<< madeChange f' RmChange 		void $ liftIO cleanup 		 		liftAnnex $ showAction "started"@@ -206,14 +207,14 @@  onAddUnlocked :: Bool -> GetFileMatcher -> Handler onAddUnlocked symlinkssupported matcher f fs = do-	mk <- liftIO $ isPointerFile f+	mk <- liftIO $ isPointerFile $ toRawFilePath f 	case mk of 		Nothing -> onAddUnlocked' contentchanged addassociatedfile addlink samefilestatus symlinkssupported matcher f fs 		Just k -> addlink f k   where 	addassociatedfile key file =  		Database.Keys.addAssociatedFile key-			=<< inRepo (toTopFilePath file)+			=<< inRepo (toTopFilePath (toRawFilePath file)) 	samefilestatus key file status = do 		cache <- Database.Keys.getInodeCaches key 		curr <- withTSDelta $ \delta -> liftIO $ toInodeCache delta file status@@ -223,12 +224,12 @@ 			_ -> return False 	contentchanged oldkey file = do 		Database.Keys.removeAssociatedFile oldkey-			=<< inRepo (toTopFilePath file)+			=<< inRepo (toTopFilePath (toRawFilePath file)) 		unlessM (inAnnex oldkey) $ 			logStatus oldkey InfoMissing 	addlink file key = do 		mode <- liftIO $ catchMaybeIO $ fileMode <$> getFileStatus file-		liftAnnex $ stagePointerFile file mode =<< hashPointerFile key+		liftAnnex $ stagePointerFile (toRawFilePath file) mode =<< hashPointerFile key 		madeChange file $ LinkChange (Just key)  onAddUnlocked'@@ -240,7 +241,7 @@ 	-> GetFileMatcher 	-> Handler onAddUnlocked' contentchanged addassociatedfile addlink samefilestatus symlinkssupported matcher file fs = do-	v <- liftAnnex $ catKeyFile file+	v <- liftAnnex $ catKeyFile (toRawFilePath file) 	case (v, fs) of 		(Just key, Just filestatus) -> 			ifM (liftAnnex $ samefilestatus key file filestatus)@@ -270,7 +271,8 @@ 	guardSymlinkStandin mk a 		| symlinkssupported = a 		| otherwise = do-			linktarget <- liftAnnex $ getAnnexLinkTarget file+			linktarget <- liftAnnex $ getAnnexLinkTarget $+				toRawFilePath file 			case linktarget of 				Nothing -> a 				Just lt -> do@@ -287,7 +289,7 @@ onAddSymlink :: Handler onAddSymlink file filestatus = unlessIgnored file $ do 	linktarget <- liftIO (catchMaybeIO $ readSymbolicLink file)-	kv <- liftAnnex (lookupFile file)+	kv <- liftAnnex (lookupFile (toRawFilePath file)) 	onAddSymlink' linktarget kv file filestatus  onAddSymlink' :: Maybe String -> Maybe Key -> Handler@@ -299,7 +301,7 @@ 			then ensurestaged (Just link) =<< getDaemonStatus 			else do 				liftAnnex $ replaceFile file $-					makeAnnexLink link+					makeAnnexLink link . toRawFilePath 				addLink file link (Just key) 	-- other symlink, not git-annex 	go Nothing = ensurestaged linktarget =<< getDaemonStatus@@ -332,8 +334,8 @@ 		case v of 			Just (currlink, sha, _type) 				| s2w8 link == L.unpack currlink ->-					stageSymlink file sha-			_ -> stageSymlink file =<< hashSymlink link+					stageSymlink (toRawFilePath file) sha+			_ -> stageSymlink (toRawFilePath file) =<< hashSymlink link 	madeChange file $ LinkChange mk  onDel :: Handler@@ -344,12 +346,12 @@  onDel' :: FilePath -> Annex () onDel' file = do-	topfile <- inRepo (toTopFilePath file)+	topfile <- inRepo (toTopFilePath (toRawFilePath file)) 	withkey $ flip Database.Keys.removeAssociatedFile topfile 	Annex.Queue.addUpdateIndex =<< 		inRepo (Git.UpdateIndex.unstageFile file)   where-	withkey a = maybe noop a =<< catKeyFile file+	withkey a = maybe noop a =<< catKeyFile (toRawFilePath file)  {- A directory has been deleted, or moved, so tell git to remove anything  - that was inside it from its cache. Since it could reappear at any time,@@ -360,14 +362,15 @@ onDelDir :: Handler onDelDir dir _ = do 	debug ["directory deleted", dir]-	(fs, clean) <- liftAnnex $ inRepo $ LsFiles.deleted [dir]+	(fs, clean) <- liftAnnex $ inRepo $ LsFiles.deleted [toRawFilePath dir]+	let fs' = map fromRawFilePath fs -	liftAnnex $ mapM_ onDel' fs+	liftAnnex $ mapM_ onDel' fs'  	-- Get the events queued up as fast as possible, so the 	-- committer sees them all in one block. 	now <- liftIO getCurrentTime-	recordChanges $ map (\f -> Change now f RmChange) fs+	recordChanges $ map (\f -> Change now f RmChange) fs'  	void $ liftIO clean 	noChange
Assistant/Threads/WebApp.hs view
@@ -100,7 +100,7 @@ 	getreldir 		| noannex = return Nothing 		| otherwise = Just <$>-			(relHome =<< absPath+			(relHome =<< absPath . fromRawFilePath 				=<< getAnnex' (fromRepo repoPath)) 	go tlssettings addr webapp htmlshim urlfile = do 		let url = myUrl tlssettings webapp addr
Assistant/TransferSlots.hs view
@@ -161,7 +161,7 @@ 				AssociatedFile Nothing -> noop 				AssociatedFile (Just af) -> void $  					addAlert $ makeAlertFiller True $-						transferFileAlert direction True af+						transferFileAlert direction True (fromRawFilePath af) 			unless isdownload $ 				handleDrops 					("object uploaded to " ++ show remote)
Assistant/Unused.hs view
@@ -64,7 +64,7 @@  	sumkeysize s k = s + fromMaybe 0 (fromKey keySize k) -	forpath a = inRepo $ liftIO . a . Git.repoPath+	forpath a = inRepo $ liftIO . a . fromRawFilePath . Git.repoPath  {- With a duration, expires all unused files that are older.  - With Nothing, expires *all* unused files. -}
Assistant/Upgrade.hs view
@@ -87,7 +87,7 @@ 		hook <- asIO1 $ distributionDownloadComplete d dest cleanup 		modifyDaemonStatus_ $ \s -> s 			{ transferHook = M.insert k hook (transferHook s) }-		maybe noop (queueTransfer "upgrade" Next (AssociatedFile (Just f)) t)+		maybe noop (queueTransfer "upgrade" Next (AssociatedFile (Just (toRawFilePath f))) t) 			=<< liftAnnex (remoteFromUUID webUUID) 		startTransfer t 	k = mkKey $ const $ distributionKey d@@ -113,7 +113,7 @@ 	| transferDirection t == Download = do 		debug ["finished downloading git-annex distribution"] 		maybe (failedupgrade "bad download") go-			=<< liftAnnex (withObjectLoc k fsckit)+			=<< liftAnnex (withObjectLoc k (fsckit . fromRawFilePath)) 	| otherwise = cleanup   where 	k = mkKey $ const $ distributionKey d
Assistant/WebApp/Configurators/Delete.hs view
@@ -78,7 +78,7 @@ 			sanityVerifierAForm $ SanityVerifier magicphrase 	case result of 		FormSuccess _ -> liftH $ do-			dir <- liftAnnex $ fromRepo Git.repoPath+			dir <- liftAnnex $ fromRawFilePath <$> fromRepo Git.repoPath 			liftIO $ removeAutoStartFile dir  			{- Disable syncing to this repository, and all
Assistant/WebApp/Configurators/Edit.hs view
@@ -101,11 +101,12 @@ 			 - there's not. Special remotes don't normally 			 - have that, and don't use it. Temporarily add 			 - it if it's missing. -}-			let remotefetch = "remote." ++ T.unpack (repoName oldc) ++ ".fetch"+			let remotefetch = Git.ConfigKey $ encodeBS' $+				"remote." ++ T.unpack (repoName oldc) ++ ".fetch" 			needfetch <- isNothing <$> fromRepo (Git.Config.getMaybe remotefetch) 			when needfetch $ 				inRepo $ Git.Command.run-					[Param "config", Param remotefetch, Param ""]+					[Param "config", Param (Git.fromConfigKey remotefetch), Param ""] 			inRepo $ Git.Command.run 				[ Param "remote" 				, Param "rename"@@ -237,7 +238,7 @@ 		RepoGroupStandard gr -> case associatedDirectory repoconfig gr of 			Just d -> inRepo $ \g -> 				createDirectoryIfMissing True $-					Git.repoPath g </> d+					fromRawFilePath (Git.repoPath g) </> d 			Nothing -> noop 		_ -> noop 
Assistant/WebApp/Configurators/Local.hs view
@@ -336,7 +336,7 @@ 		isnew <- liftIO $ makeRepo dir True 		{- Removable drives are not reliable media, so enable fsync. -} 		liftIO $ inDir dir $-			setConfig (ConfigKey "core.fsyncobjectfiles")+			setConfig "core.fsyncobjectfiles" 				(Git.Config.boolConfig True) 		(u, r) <- a isnew 		when isnew $
Assistant/WebApp/Configurators/Pairing.hs view
@@ -173,7 +173,7 @@ postFinishLocalPairR :: PairMsg -> Handler Html #ifdef WITH_PAIRING postFinishLocalPairR msg = promptSecret (Just msg) $ \_ secret -> do-	repodir <- liftH $ repoPath <$> liftAnnex gitRepo+	repodir <- liftH $ fromRawFilePath . repoPath <$> liftAnnex gitRepo 	liftIO $ setup repodir 	startLocalPairing PairAck (cleanup repodir) alert uuid "" secret   where
Assistant/WebApp/Configurators/Preferences.hs view
@@ -94,7 +94,7 @@ 	unsetConfig (annexConfig "numcopies") -- deprecated 	setConfig (annexConfig "autoupgrade") (fromAutoUpgrade $ autoUpgrade p) 	unlessM ((==) <$> pure (autoStart p) <*> inAutoStartFile) $ do-		here <- fromRepo Git.repoPath+		here <- fromRawFilePath <$> fromRepo Git.repoPath 		liftIO $ if autoStart p 			then addAutoStartFile here 			else removeAutoStartFile here@@ -118,5 +118,5 @@  inAutoStartFile :: Annex Bool inAutoStartFile = do-	here <- liftIO . absPath =<< fromRepo Git.repoPath+	here <- liftIO . absPath . fromRawFilePath =<< fromRepo Git.repoPath 	any (`equalFilePath` here) <$> liftIO readAutoStartFile
Assistant/WebApp/Configurators/Ssh.hs view
@@ -20,7 +20,7 @@ import Utility.UserInfo import Utility.Gpg import Types.Remote (RemoteConfig)-import Git.Types (RemoteName, fromRef)+import Git.Types (RemoteName, fromRef, fromConfigKey) import qualified Remote.GCrypt as GCrypt import qualified Annex import qualified Git.Command@@ -317,7 +317,8 @@ 				else T.pack $ "Failed to ssh to the server. Transcript: " ++ s 		finduuid (k, v) 			| k == "annex.uuid" = Just $ toUUID v-			| k == GCrypt.coreGCryptId = Just $ genUUIDInNameSpace gCryptNameSpace v+			| k == fromConfigKey GCrypt.coreGCryptId =+				Just $ genUUIDInNameSpace gCryptNameSpace v 			| otherwise = Nothing 	 	checkcommand c = "if which " ++ c ++ "; then " ++ report c ++ "; fi"
Assistant/WebApp/DashBoard.hs view
@@ -45,7 +45,7 @@ 		transferPaused info || isNothing (startedTime info) 	desc transfer info = case associatedFile info of 		AssociatedFile Nothing -> serializeKey $ transferKey transfer-		AssociatedFile (Just af) -> af+		AssociatedFile (Just af) -> fromRawFilePath af  {- Simplifies a list of transfers, avoiding display of redundant  - equivilant transfers. -}@@ -118,7 +118,8 @@  - blocking the response to the browser on it. -} openFileBrowser :: Handler Bool openFileBrowser = do-	path <- liftIO . absPath =<< liftAnnex (fromRepo Git.repoPath)+	path <- liftIO . absPath . fromRawFilePath+		=<< liftAnnex (fromRepo Git.repoPath) #ifdef darwin_HOST_OS 	let cmd = "open" 	let p = proc cmd [path]
Backend/Hash.hs view
@@ -188,7 +188,7 @@ 		AssociatedFile Nothing -> Nothing 		AssociatedFile (Just file) -> Just $ alterKey oldkey $ \d -> d 			{ keyName = keyHash oldkey -				<> encodeBS (selectExtension maxextlen file)+				<> encodeBS' (selectExtension maxextlen (fromRawFilePath file)) 			, keyVariety = newvariety 			} 	{- Upgrade to fix bad previous migration that created a
Backend/Utilities.hs view
@@ -11,6 +11,7 @@ import Utility.Hash  import qualified Data.ByteString as S+import qualified Data.ByteString.Lazy as L  {- Generates a keyName from an input string. Takes care of sanitizing it.  - If it's not too long, the full string is used as the keyName.@@ -21,11 +22,12 @@ 	-- Avoid making keys longer than the length of a SHA256 checksum. 	| bytelen > sha256len = encodeBS' $ 		truncateFilePath (sha256len - md5len - 1) s' ++ "-" ++ -			show (md5 (encodeBL s))+			show (md5 bl) 	| otherwise = encodeBS' s'   where 	s' = preSanitizeKeyName s-	bytelen = length (decodeW8 s')+	bl = encodeBL s+	bytelen = fromIntegral $ L.length bl  	sha256len = 64 	md5len = 32
Backend/WORM.hs view
@@ -38,7 +38,8 @@ 	let f = contentLocation source 	stat <- liftIO $ getFileStatus f 	sz <- liftIO $ getFileSize' f stat-	relf <- getTopFilePath <$> inRepo (toTopFilePath $ keyFilename source)+	relf <- fromRawFilePath . getTopFilePath+		<$> inRepo (toTopFilePath $ toRawFilePath $ keyFilename source) 	return $ Just $ mkKey $ \k -> k 		{ keyName = genKeyName relf 		, keyVariety = WORMKey
CHANGELOG view
@@ -1,3 +1,31 @@+git-annex (7.20191230) upstream; urgency=medium++  * Optimised processing of many files, especially by commands like find+    and whereis that only report on the state of the repository. Commands+    like get also sped up in cases where they have to check a lot of+    files but only transfer a few files. Speedups range from 30-100%.+  * Added build dependency on the filepath-bytestring library.+  * Fixed an oversight that had always prevented annex.resolvemerge+    from being honored, when it was configured by git-annex config.+  * annex.largefiles can be configured by git-annex config,+    to more easily set a default that will also be used by clones,+    without needing to shoehorn the expression into the gitattributes file.+    The git config and gitattributes override that.+  * annex.addunlocked can be set to an expression with the same format used by+    annex.largefiles, when you want to default to unlocking some files but+    not others.+  * annex.addunlocked can be configured by git-annex config.+  * git-annex-config --set/--unset: No longer change the local git config+    setting, except for in the special case of annex.securehashesonly.+  * Improve file ordering behavior when one parameter is "." and other+    parameters are other directories.+  * smudge bugfix: When annex.largefiles=anything, files that were already+    stored in git, and have not been modified could sometimes be converted+    to being stored in the annex. Changes in 7.20191024 made this more+    of a problem. This case is now detected and prevented.++ -- Joey Hess <id@joeyh.name>  Mon, 30 Dec 2019 12:43:30 -0400+ git-annex (7.20191218) upstream; urgency=medium    * git-lfs: The url provided to initremote/enableremote will now be
@@ -29,6 +29,11 @@            2013 Michael Snoyman License: Expat +Files: Utility/Attoparsec.hs+Copyright: 2019 Joey Hess <id@joeyh.name>+           2007-2015 Bryan O'Sullivan+License: BSD-3-clause+ Files: Utility/GitLFS.hs Copyright: © 2019 Joey Hess <id@joeyh.name> License: AGPL-3+@@ -112,7 +117,35 @@  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY  OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF  SUCH DAMAGE.- ++License: BSD-3-clause+ Redistribution and use in source and binary forms, with or without+ modification, are permitted provided that the following conditions+ are met:+ .+ 1. Redistributions of source code must retain the above copyright+     notice, this list of conditions and the following disclaimer.+ .+ 2. Redistributions in binary form must reproduce the above copyright+    notice, this list of conditions and the following disclaimer in the+    documentation and/or other materials provided with the distribution.+ .+ 3. Neither the name of the author nor the names of his contributors+    may be used to endorse or promote products derived from this software+    without specific prior written permission.+ .+ THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND ANY EXPRESS+ OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE+ DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS+ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN+ ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE+ POSSIBILITY OF SUCH DAMAGE.+ License: Expat  Permission is hereby granted, free of charge, to any person obtaining  a copy of this software and associated documentation files (the
CmdLine/Batch.hs view
@@ -102,7 +102,8 @@ batchFilesMatching fmt a = do 	matcher <- getMatcher 	batchStart fmt $ \f ->-		ifM (matcher $ MatchingFile $ FileInfo f f)+		let f' = toRawFilePath f+		in ifM (matcher $ MatchingFile $ FileInfo f' f') 			( a f 			, return Nothing 			)
CmdLine/GitAnnex/Options.hs view
@@ -92,7 +92,7 @@   where 	setnumcopies n = Annex.changeState $ \s -> s { Annex.forcenumcopies = Just $ NumCopies n } 	setuseragent v = Annex.changeState $ \s -> s { Annex.useragent = Just v }-	setgitconfig v = Annex.adjustGitRepo $ \r -> Git.Config.store v $ +	setgitconfig v = Annex.adjustGitRepo $ \r -> Git.Config.store (encodeBS' v) $  		r { gitGlobalOpts = gitGlobalOpts r ++ [Param "-c", Param v] } 	setdesktopnotify v = Annex.changeState $ \s -> s { Annex.desktopnotify = Annex.desktopnotify s <> v } 
CmdLine/GitAnnexShell/Fields.hs view
@@ -30,7 +30,7 @@ associatedFile :: Field associatedFile = Field "associatedfile" $ \f -> 	-- is the file a safe relative filename?-	not (absoluteGitPath f) && not ("../" `isPrefixOf` f)+	not (absoluteGitPath (toRawFilePath f)) && not ("../" `isPrefixOf` f)  direct :: Field direct = Field "direct" $ \f -> f == "1"
CmdLine/Seek.hs view
@@ -33,12 +33,13 @@ import Annex.Content import Annex.InodeSentinal import qualified Database.Keys+import qualified Utility.RawFilePath as R -withFilesInGit :: (FilePath -> CommandSeek) -> [WorkTreeItem] -> CommandSeek+withFilesInGit :: (RawFilePath -> CommandSeek) -> [WorkTreeItem] -> CommandSeek withFilesInGit a l = seekActions $ prepFiltered a $ 	seekHelper LsFiles.inRepo l -withFilesInGitNonRecursive :: String -> (FilePath -> CommandSeek) -> [WorkTreeItem] -> CommandSeek+withFilesInGitNonRecursive :: String -> (RawFilePath -> CommandSeek) -> [WorkTreeItem] -> CommandSeek withFilesInGitNonRecursive needforce a l = ifM (Annex.getState Annex.force) 	( withFilesInGit a l 	, if null l@@ -48,7 +49,7 @@   where 	getfiles c [] = return (reverse c) 	getfiles c ((WorkTreeItem p):ps) = do-		(fs, cleanup) <- inRepo $ LsFiles.inRepo [p]+		(fs, cleanup) <- inRepo $ LsFiles.inRepo [toRawFilePath p] 		case fs of 			[f] -> do 				void $ liftIO $ cleanup@@ -58,11 +59,11 @@ 				getfiles c ps 			_ -> giveup needforce -withFilesNotInGit :: Bool -> (FilePath -> CommandSeek) -> [WorkTreeItem] -> CommandSeek+withFilesNotInGit :: Bool -> (RawFilePath -> CommandSeek) -> [WorkTreeItem] -> CommandSeek withFilesNotInGit skipdotfiles a l 	| skipdotfiles = do 		{- dotfiles are not acted on unless explicitly listed -}-		files <- filter (not . dotfile) <$>+		files <- filter (not . dotfile . fromRawFilePath) <$> 			seekunless (null ps && not (null l)) ps 		dotfiles <- seekunless (null dotps) dotps 		go (files++dotfiles)@@ -74,9 +75,9 @@ 		force <- Annex.getState Annex.force 		g <- gitRepo 		liftIO $ Git.Command.leaveZombie-			<$> LsFiles.notInRepo force (map (\(WorkTreeItem f) -> f) l') g+			<$> LsFiles.notInRepo force (map (\(WorkTreeItem f) -> toRawFilePath f) l') g 	go fs = seekActions $ prepFiltered a $-		return $ concat $ segmentPaths (map (\(WorkTreeItem f) -> f) l) fs+		return $ concat $ segmentPaths (map (\(WorkTreeItem f) -> toRawFilePath f) l) fs  withPathContents :: ((FilePath, FilePath) -> CommandSeek) -> CmdParams -> CommandSeek withPathContents a params = do@@ -93,8 +94,8 @@ 		, return [(p, takeFileName p)] 		) 	checkmatch matcher (f, relf) = matcher $ MatchingFile $ FileInfo-		{ currFile = f-		, matchFile = relf+		{ currFile = toRawFilePath f+		, matchFile = toRawFilePath relf 		}  withWords :: ([String] -> CommandSeek) -> CmdParams -> CommandSeek@@ -110,30 +111,30 @@ 	pairs c (x:y:xs) = pairs ((x,y):c) xs 	pairs _ _ = giveup "expected pairs" -withFilesToBeCommitted :: (FilePath -> CommandSeek) -> [WorkTreeItem] -> CommandSeek+withFilesToBeCommitted :: (RawFilePath -> CommandSeek) -> [WorkTreeItem] -> CommandSeek withFilesToBeCommitted a l = seekActions $ prepFiltered a $ 	seekHelper LsFiles.stagedNotDeleted l -isOldUnlocked :: FilePath -> Annex Bool+isOldUnlocked :: RawFilePath -> Annex Bool isOldUnlocked f = liftIO (notSymlink f) <&&>  	(isJust <$> catKeyFile f <||> isJust <$> catKeyFileHEAD f)  {- unlocked pointer files that are staged, and whose content has not been  - modified-}-withUnmodifiedUnlockedPointers :: (FilePath -> CommandSeek) -> [WorkTreeItem] -> CommandSeek+withUnmodifiedUnlockedPointers :: (RawFilePath -> CommandSeek) -> [WorkTreeItem] -> CommandSeek withUnmodifiedUnlockedPointers a l = seekActions $ 	prepFiltered a unlockedfiles   where 	unlockedfiles = filterM isUnmodifiedUnlocked  		=<< seekHelper LsFiles.typeChangedStaged l -isUnmodifiedUnlocked :: FilePath -> Annex Bool+isUnmodifiedUnlocked :: RawFilePath -> Annex Bool isUnmodifiedUnlocked f = catKeyFile f >>= \case 	Nothing -> return False 	Just k -> sameInodeCache f =<< Database.Keys.getInodeCaches k  {- Finds files that may be modified. -}-withFilesMaybeModified :: (FilePath -> CommandSeek) -> [WorkTreeItem] -> CommandSeek+withFilesMaybeModified :: (RawFilePath -> CommandSeek) -> [WorkTreeItem] -> CommandSeek withFilesMaybeModified a params = seekActions $ 	prepFiltered a $ seekHelper LsFiles.modified params @@ -225,20 +226,21 @@ 		forM_ ts $ \(t, i) -> 			keyaction (transferKey t, mkActionItem (t, i)) -prepFiltered :: (FilePath -> CommandSeek) -> Annex [FilePath] -> Annex [CommandSeek]+prepFiltered :: (RawFilePath -> CommandSeek) -> Annex [RawFilePath] -> Annex [CommandSeek] prepFiltered a fs = do 	matcher <- Limit.getMatcher 	map (process matcher) <$> fs   where-	process matcher f = whenM (matcher $ MatchingFile $ FileInfo f f) $ a f+	process matcher f =+		whenM (matcher $ MatchingFile $ FileInfo f f) $ a f  seekActions :: Annex [CommandSeek] -> Annex () seekActions gen = sequence_ =<< gen -seekHelper :: ([FilePath] -> Git.Repo -> IO ([FilePath], IO Bool)) -> [WorkTreeItem] -> Annex [FilePath]+seekHelper :: ([RawFilePath] -> Git.Repo -> IO ([RawFilePath], IO Bool)) -> [WorkTreeItem] -> Annex [RawFilePath] seekHelper a l = inRepo $ \g -> 	concat . concat <$> forM (segmentXargsOrdered l')-		(runSegmentPaths (\fs -> Git.Command.leaveZombie <$> a fs g))+		(runSegmentPaths (\fs -> Git.Command.leaveZombie <$> a fs g) . map toRawFilePath)   where 	l' = map (\(WorkTreeItem f) -> f) l @@ -264,14 +266,14 @@ 		unlessM (exists p <||> hidden currbranch p) $ do 			toplevelWarning False (p ++ " not found") 			Annex.incError-	return (map WorkTreeItem ps)+	return (map (WorkTreeItem) ps)   where 	exists p = isJust <$> liftIO (catchMaybeIO $ getSymbolicLinkStatus p) 	hidden currbranch p 		| allowhidden = do 			f <- liftIO $ relPathCwdToFile p-			isJust <$> catObjectMetaDataHidden f currbranch+			isJust <$> catObjectMetaDataHidden (toRawFilePath f) currbranch 		| otherwise = return False -notSymlink :: FilePath -> IO Bool-notSymlink f = liftIO $ not . isSymbolicLink <$> getSymbolicLinkStatus f+notSymlink :: RawFilePath -> IO Bool+notSymlink f = liftIO $ not . isSymbolicLink <$> R.getSymbolicLinkStatus f
Command/Add.hs view
@@ -19,6 +19,7 @@ import Annex.Tmp import Messages.Progress import Git.FilePath+import qualified Utility.RawFilePath as R  cmd :: Command cmd = notBareRepo $ @@ -49,9 +50,10 @@  seek :: AddOptions -> CommandSeek seek o = startConcurrency commandStages $ do-	matcher <- largeFilesMatcher-	let gofile file = ifM (checkFileMatcher matcher file <||> Annex.getState Annex.force)-		( start file+	largematcher <- largeFilesMatcher+	addunlockedmatcher <- addUnlockedMatcher+	let gofile file = ifM (checkFileMatcher largematcher (fromRawFilePath file) <||> Annex.getState Annex.force)+		( start file addunlockedmatcher 		, ifM (annexAddSmallFiles <$> Annex.getGitConfig) 			( startSmall file 			, stop@@ -61,7 +63,7 @@ 		Batch fmt 			| updateOnly o -> 				giveup "--update --batch is not supported"-			| otherwise -> batchFilesMatching fmt gofile+			| otherwise -> batchFilesMatching fmt (gofile . toRawFilePath) 		NoBatch -> do 			l <- workTreeItems (addThese o) 			let go a = a (commandAction . gofile) l@@ -71,28 +73,28 @@ 			go withUnmodifiedUnlockedPointers  {- Pass file off to git-add. -}-startSmall :: FilePath -> CommandStart+startSmall :: RawFilePath -> CommandStart startSmall file = starting "add" (ActionItemWorkTreeFile file) $ 	next $ addSmall file -addSmall :: FilePath -> Annex Bool+addSmall :: RawFilePath -> Annex Bool addSmall file = do 	showNote "non-large file; adding content to git repository" 	addFile file -addFile :: FilePath -> Annex Bool+addFile :: RawFilePath -> Annex Bool addFile file = do 	ps <- forceParams-	Annex.Queue.addCommand "add" (ps++[Param "--"]) [file]+	Annex.Queue.addCommand "add" (ps++[Param "--"]) [fromRawFilePath file] 	return True -start :: FilePath -> CommandStart-start file = do+start :: RawFilePath -> AddUnlockedMatcher -> CommandStart+start file addunlockedmatcher = do 	mk <- liftIO $ isPointerFile file 	maybe go fixuppointer mk   where 	go = ifAnnexed file addpresent add-	add = liftIO (catchMaybeIO $ getSymbolicLinkStatus file) >>= \case+	add = liftIO (catchMaybeIO $ R.getSymbolicLinkStatus file) >>= \case 		Nothing -> stop 		Just s  			| not (isRegularFile s) && not (isSymbolicLink s) -> stop@@ -100,15 +102,15 @@ 				starting "add" (ActionItemWorkTreeFile file) $ 					if isSymbolicLink s 						then next $ addFile file-						else perform file+						else perform file addunlockedmatcher 	addpresent key = -		liftIO (catchMaybeIO $ getSymbolicLinkStatus file) >>= \case+		liftIO (catchMaybeIO $ R.getSymbolicLinkStatus file) >>= \case 			Just s | isSymbolicLink s -> fixuplink key 			_ -> add 	fixuplink key = starting "add" (ActionItemWorkTreeFile file) $ do 		-- the annexed symlink is present but not yet added to git-		liftIO $ removeFile file-		addLink file key Nothing+		liftIO $ removeFile (fromRawFilePath file)+		addLink (fromRawFilePath file) key Nothing 		next $ 			cleanup key =<< inAnnex key 	fixuppointer key = starting "add" (ActionItemWorkTreeFile file) $ do@@ -116,14 +118,15 @@ 		Database.Keys.addAssociatedFile key =<< inRepo (toTopFilePath file) 		next $ addFile file -perform :: FilePath -> CommandPerform-perform file = withOtherTmp $ \tmpdir -> do-	lockingfile <- not <$> addUnlocked+perform :: RawFilePath -> AddUnlockedMatcher -> CommandPerform+perform file addunlockedmatcher = withOtherTmp $ \tmpdir -> do+	lockingfile <- not <$> addUnlocked addunlockedmatcher+		(MatchingFile (FileInfo file file)) 	let cfg = LockDownConfig 		{ lockingFile = lockingfile 		, hardlinkFileTmpDir = Just tmpdir 		}-	ld <- lockDown cfg file+	ld <- lockDown cfg (fromRawFilePath file) 	let sizer = keySource <$> ld 	v <- metered Nothing sizer $ \_meter meterupdate -> 		ingestAdd meterupdate ld
Command/AddUnused.hs view
@@ -31,7 +31,7 @@ 	addLink file key Nothing 	return True   where-	file = "unused." ++ keyFile key+	file = "unused." ++ fromRawFilePath (keyFile key)  {- The content is not in the annex, but in another directory, and  - it seems better to error out, rather than moving bad/tmp content into
Command/AddUrl.hs view
@@ -94,16 +94,16 @@  seek :: AddUrlOptions -> CommandSeek seek o = startConcurrency commandStages $ do+	addunlockedmatcher <- addUnlockedMatcher+	let go (o', u) = do+		r <- Remote.claimingUrl u+		if Remote.uuid r == webUUID || rawOption (downloadOptions o')+			then void $ commandAction $ startWeb addunlockedmatcher o' u+			else checkUrl addunlockedmatcher r o' u 	forM_ (addUrls o) (\u -> go (o, u)) 	case batchOption o of 		Batch fmt -> batchInput fmt (parseBatchInput o) go 		NoBatch -> noop-  where-	go (o', u) = do-		r <- Remote.claimingUrl u-		if Remote.uuid r == webUUID || rawOption (downloadOptions o')-			then void $ commandAction $ startWeb o' u-			else checkUrl r o' u  parseBatchInput :: AddUrlOptions -> String -> Either String (AddUrlOptions, URLString) parseBatchInput o s@@ -114,8 +114,8 @@ 			else Right (o { downloadOptions = (downloadOptions o) { fileOption = Just f } }, u) 	| otherwise = Right (o, s) -checkUrl :: Remote -> AddUrlOptions -> URLString -> Annex ()-checkUrl r o u = do+checkUrl :: AddUnlockedMatcher -> Remote -> AddUrlOptions -> URLString -> Annex ()+checkUrl addunlockedmatcher r o u = do 	pathmax <- liftIO $ fileNameLengthLimit "." 	let deffile = fromMaybe (urlString2file u (pathdepthOption o) pathmax) (fileOption (downloadOptions o)) 	go deffile =<< maybe@@ -129,49 +129,49 @@ 		next $ return False 	go deffile (Right (UrlContents sz mf)) = do 		let f = adjustFile o (fromMaybe (maybe deffile fromSafeFilePath mf) (fileOption (downloadOptions o)))-		void $ commandAction $ startRemote r o f u sz+		void $ commandAction $ startRemote addunlockedmatcher r o f u sz 	go deffile (Right (UrlMulti l)) = case fileOption (downloadOptions o) of 		Nothing -> 			forM_ l $ \(u', sz, f) -> do 				let f' = adjustFile o (deffile </> fromSafeFilePath f)-				void $ commandAction $ startRemote r o f' u' sz+				void $ commandAction $ startRemote addunlockedmatcher r o f' u' sz 		Just f -> case l of 			[] -> noop 			((u',sz,_):[]) -> do 				let f' = adjustFile o f-				void $ commandAction $ startRemote r o f' u' sz+				void $ commandAction $ startRemote addunlockedmatcher r o f' u' sz 			_ -> giveup $ unwords 				[ "That url contains multiple files according to the" 				, Remote.name r 				, " remote; cannot add it to a single file." 				] -startRemote :: Remote -> AddUrlOptions -> FilePath -> URLString -> Maybe Integer -> CommandStart-startRemote r o file uri sz = do+startRemote :: AddUnlockedMatcher -> Remote -> AddUrlOptions -> FilePath -> URLString -> Maybe Integer -> CommandStart+startRemote addunlockedmatcher r o file uri sz = do 	pathmax <- liftIO $ fileNameLengthLimit "." 	let file' = joinPath $ map (truncateFilePath pathmax) $ splitDirectories file 	startingAddUrl uri o $ do 		showNote $ "from " ++ Remote.name r  		showDestinationFile file'-		performRemote r o uri file' sz+		performRemote addunlockedmatcher r o uri file' sz -performRemote :: Remote -> AddUrlOptions -> URLString -> FilePath -> Maybe Integer -> CommandPerform-performRemote r o uri file sz = ifAnnexed file adduri geturi+performRemote :: AddUnlockedMatcher -> Remote -> AddUrlOptions -> URLString -> FilePath -> Maybe Integer -> CommandPerform+performRemote addunlockedmatcher r o uri file sz = ifAnnexed (toRawFilePath file) adduri geturi   where 	loguri = setDownloader uri OtherDownloader 	adduri = addUrlChecked o loguri file (Remote.uuid r) checkexistssize 	checkexistssize key = return $ case sz of 		Nothing -> (True, True, loguri) 		Just n -> (True, n == fromMaybe n (fromKey keySize key), loguri)-	geturi = next $ isJust <$> downloadRemoteFile r (downloadOptions o) uri file sz+	geturi = next $ isJust <$> downloadRemoteFile addunlockedmatcher r (downloadOptions o) uri file sz -downloadRemoteFile :: Remote -> DownloadOptions -> URLString -> FilePath -> Maybe Integer -> Annex (Maybe Key)-downloadRemoteFile r o uri file sz = checkCanAdd file $ do+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) 	ifM (Annex.getState Annex.fast <||> pure (relaxedOption o)) 		( do-			addWorkTree (Remote.uuid r) loguri file urlkey Nothing+			addWorkTree addunlockedmatcher (Remote.uuid r) loguri file urlkey Nothing 			return (Just urlkey) 		, do 			-- Set temporary url for the urlkey@@ -180,16 +180,16 @@ 			setTempUrl urlkey loguri 			let downloader = \dest p -> fst  				<$> Remote.retrieveKeyFile r urlkey-					(AssociatedFile (Just file)) dest p-			ret <- downloadWith downloader urlkey (Remote.uuid r) loguri file+					(AssociatedFile (Just (toRawFilePath file))) dest p+			ret <- downloadWith addunlockedmatcher downloader urlkey (Remote.uuid r) loguri file 			removeTempUrl urlkey 			return ret 		)   where 	loguri = setDownloader uri OtherDownloader -startWeb :: AddUrlOptions -> URLString -> CommandStart-startWeb o urlstring = go $ fromMaybe bad $ parseURI urlstring+startWeb :: AddUnlockedMatcher -> AddUrlOptions -> URLString -> CommandStart+startWeb addunlockedmatcher o urlstring = go $ fromMaybe bad $ parseURI urlstring   where 	bad = fromMaybe (giveup $ "bad url " ++ urlstring) $ 		Url.parseURIRelaxed $ urlstring@@ -209,12 +209,12 @@ 						( pure $ url2file url (pathdepthOption o) pathmax 						, pure f 						)-		performWeb o urlstring file urlinfo+		performWeb addunlockedmatcher o urlstring file urlinfo -performWeb :: AddUrlOptions -> URLString -> FilePath -> Url.UrlInfo -> CommandPerform-performWeb o url file urlinfo = ifAnnexed file addurl geturl+performWeb :: AddUnlockedMatcher -> AddUrlOptions -> URLString -> FilePath -> Url.UrlInfo -> CommandPerform+performWeb addunlockedmatcher o url file urlinfo = ifAnnexed (toRawFilePath file) addurl geturl   where-	geturl = next $ isJust <$> addUrlFile (downloadOptions o) url urlinfo file+	geturl = next $ isJust <$> addUrlFile addunlockedmatcher (downloadOptions o) url urlinfo file 	addurl = addUrlChecked o url file webUUID $ \k -> 		ifM (pure (not (rawOption (downloadOptions o))) <&&> youtubeDlSupported url) 			( return (True, True, setDownloader url YoutubeDownloader)@@ -249,16 +249,16 @@  - different file, based on the title of the media. Unless the user  - specified fileOption, which then forces using the FilePath.  -}-addUrlFile :: DownloadOptions -> URLString -> Url.UrlInfo -> FilePath -> Annex (Maybe Key)-addUrlFile o url urlinfo file =+addUrlFile :: AddUnlockedMatcher -> DownloadOptions -> URLString -> Url.UrlInfo -> FilePath -> Annex (Maybe Key)+addUrlFile addunlockedmatcher o url urlinfo file = 	ifM (Annex.getState Annex.fast <||> pure (relaxedOption o))-		( nodownloadWeb o url urlinfo file-		, downloadWeb o url urlinfo file+		( nodownloadWeb addunlockedmatcher o url urlinfo file+		, downloadWeb addunlockedmatcher o url urlinfo file 		) -downloadWeb :: DownloadOptions -> URLString -> Url.UrlInfo -> FilePath -> Annex (Maybe Key)-downloadWeb o url urlinfo file =-	go =<< downloadWith' downloader urlkey webUUID url (AssociatedFile (Just file))+downloadWeb :: AddUnlockedMatcher -> DownloadOptions -> URLString -> Url.UrlInfo -> FilePath -> Annex (Maybe Key)+downloadWeb addunlockedmatcher o url urlinfo file =+	go =<< downloadWith' downloader urlkey webUUID url (AssociatedFile (Just (toRawFilePath file)))   where 	urlkey = addSizeUrlKey urlinfo $ Backend.URL.fromUrl url Nothing 	downloader f p = downloadUrl urlkey p [url] f@@ -272,13 +272,13 @@ 	normalfinish tmp = checkCanAdd file $ do 		showDestinationFile file 		liftIO $ createDirectoryIfMissing True (parentDir file)-		finishDownloadWith tmp webUUID url file+		finishDownloadWith addunlockedmatcher tmp webUUID url file 	tryyoutubedl tmp 		-- Ask youtube-dl what filename it will download 		-- first, and check if that is already an annexed file, 		-- to avoid unnecessary work in that case. 		| otherwise = youtubeDlFileNameHtmlOnly url >>= \case-			Right dest -> ifAnnexed dest +			Right dest -> ifAnnexed (toRawFilePath dest) 				(alreadyannexed dest) 				(dl dest) 			Left _ -> normalfinish tmp@@ -298,7 +298,7 @@ 							cleanuptmp 							checkCanAdd dest $ do 								showDestinationFile dest-								addWorkTree webUUID mediaurl dest mediakey (Just mediafile)+								addWorkTree addunlockedmatcher webUUID mediaurl dest mediakey (Just mediafile) 								return $ Just mediakey 						Right Nothing -> normalfinish tmp 						Left msg -> do@@ -341,13 +341,13 @@  - Downloads the url, sets up the worktree file, and returns the  - real key.  -}-downloadWith :: (FilePath -> MeterUpdate -> Annex Bool) -> Key -> UUID -> URLString -> FilePath -> Annex (Maybe Key)-downloadWith downloader dummykey u url file =+downloadWith :: AddUnlockedMatcher -> (FilePath -> MeterUpdate -> Annex Bool) -> Key -> UUID -> URLString -> FilePath -> Annex (Maybe Key)+downloadWith addunlockedmatcher downloader dummykey u url file = 	go =<< downloadWith' downloader dummykey u url afile   where-	afile = AssociatedFile (Just file)+	afile = AssociatedFile (Just (toRawFilePath file)) 	go Nothing = return Nothing-	go (Just tmp) = finishDownloadWith tmp u url file+	go (Just tmp) = finishDownloadWith addunlockedmatcher tmp u url file  {- Like downloadWith, but leaves the dummy key content in  - the returned location. -}@@ -363,8 +363,8 @@ 			then return (Just tmp) 			else return Nothing -finishDownloadWith :: FilePath -> UUID -> URLString -> FilePath -> Annex (Maybe Key)-finishDownloadWith tmp u url file = do+finishDownloadWith :: AddUnlockedMatcher -> FilePath -> UUID -> URLString -> FilePath -> Annex (Maybe Key)+finishDownloadWith addunlockedmatcher tmp u url file = do 	backend <- chooseBackend file 	let source = KeySource 		{ keyFilename = file@@ -374,7 +374,7 @@ 	genKey source nullMeterUpdate backend >>= \case 		Nothing -> return Nothing 		Just (key, _) -> do-			addWorkTree u url file key (Just tmp)+			addWorkTree addunlockedmatcher u url file key (Just tmp) 			return (Just key)  {- Adds the url size to the Key. -}@@ -384,8 +384,8 @@ 	}  {- Adds worktree file to the repository. -}-addWorkTree :: UUID -> URLString -> FilePath -> Key -> Maybe FilePath -> Annex ()-addWorkTree u url file key mtmp = case mtmp of+addWorkTree :: AddUnlockedMatcher -> UUID -> URLString -> FilePath -> Key -> Maybe FilePath -> Annex ()+addWorkTree addunlockedmatcher u url file key mtmp = case mtmp of 	Nothing -> go 	Just tmp -> do 		-- Move to final location for large file check.@@ -401,21 +401,21 @@ 				-- than the work tree file. 				liftIO $ renameFile file tmp 				go-			else void $ Command.Add.addSmall file+			else void $ Command.Add.addSmall (toRawFilePath file)   where 	go = do 		maybeShowJSON $ JSONChunk [("key", serializeKey key)] 		setUrlPresent key url 		logChange key u InfoPresent-		ifM (addAnnexedFile file key mtmp)+		ifM (addAnnexedFile addunlockedmatcher file key mtmp) 			( do 				when (isJust mtmp) $ 					logStatus key InfoPresent 			, maybe noop (\tmp -> pruneTmpWorkDirBefore tmp (liftIO . nukeFile)) mtmp 			) -nodownloadWeb :: DownloadOptions -> URLString -> Url.UrlInfo -> FilePath -> Annex (Maybe Key)-nodownloadWeb o url urlinfo file+nodownloadWeb :: AddUnlockedMatcher -> DownloadOptions -> URLString -> Url.UrlInfo -> FilePath -> Annex (Maybe Key)+nodownloadWeb addunlockedmatcher o url urlinfo file 	| Url.urlExists urlinfo = if rawOption o 		then nomedia 		else either (const nomedia) usemedia@@ -426,20 +426,20 @@   where 	nomedia = do 		let key = Backend.URL.fromUrl url (Url.urlSize urlinfo)-		nodownloadWeb' url key file+		nodownloadWeb' addunlockedmatcher url key file 	usemedia mediafile = do 		let dest = if isJust (fileOption o) 			then file 			else takeFileName mediafile 		let mediaurl = setDownloader url YoutubeDownloader 		let mediakey = Backend.URL.fromUrl mediaurl Nothing-		nodownloadWeb' mediaurl mediakey dest+		nodownloadWeb' addunlockedmatcher mediaurl mediakey dest -nodownloadWeb' :: URLString -> Key -> FilePath -> Annex (Maybe Key)-nodownloadWeb' url key file = checkCanAdd file $ do+nodownloadWeb' :: AddUnlockedMatcher -> URLString -> Key -> FilePath -> Annex (Maybe Key)+nodownloadWeb' addunlockedmatcher url key file = checkCanAdd file $ do 	showDestinationFile file 	liftIO $ createDirectoryIfMissing True (parentDir file)-	addWorkTree webUUID url file key Nothing+	addWorkTree addunlockedmatcher webUUID url file key Nothing 	return (Just key)  url2file :: URI -> Maybe Int -> Int -> FilePath
Command/Config.hs view
@@ -5,21 +5,26 @@  - Licensed under the GNU AGPL version 3 or higher.  -} +{-# LANGUAGE OverloadedStrings #-}+ module Command.Config where  import Command import Logs.Config import Config+import Git.Types (ConfigKey(..), fromConfigValue) +import qualified Data.ByteString.Char8 as S8+ cmd :: Command cmd = noMessages $ command "config" SectionSetup 	"configuration stored in git-annex branch" 	paramNothing (seek <$$> optParser)  data Action-	= SetConfig ConfigName ConfigValue-	| GetConfig ConfigName-	| UnsetConfig ConfigName+	= SetConfig ConfigKey ConfigValue+	| GetConfig ConfigKey+	| UnsetConfig ConfigKey  type Name = String type Value = String@@ -48,19 +53,25 @@ 		)  seek :: Action -> CommandSeek-seek (SetConfig name val) = commandAction $-	startingUsualMessages name (ActionItemOther (Just val)) $ do-		setGlobalConfig name val-		setConfig (ConfigKey name) val+seek (SetConfig ck@(ConfigKey name) val) = commandAction $+	startingUsualMessages (decodeBS' name) (ActionItemOther (Just (fromConfigValue val))) $ do+		setGlobalConfig ck val+		when (needLocalUpdate ck) $+			setConfig ck (fromConfigValue val) 		next $ return True-seek (UnsetConfig name) = commandAction $-	startingUsualMessages name (ActionItemOther (Just "unset")) $do-		unsetGlobalConfig name-		unsetConfig (ConfigKey name)+seek (UnsetConfig ck@(ConfigKey name)) = commandAction $+	startingUsualMessages (decodeBS' name) (ActionItemOther (Just "unset")) $do+		unsetGlobalConfig ck+		when (needLocalUpdate ck) $+			unsetConfig ck 		next $ return True-seek (GetConfig name) = commandAction $+seek (GetConfig ck) = commandAction $ 	startingCustomOutput (ActionItemOther Nothing) $ do-		getGlobalConfig name >>= \case+		getGlobalConfig ck >>= \case 			Nothing -> return ()-			Just v -> liftIO $ putStrLn v+			Just (ConfigValue v) -> liftIO $ S8.putStrLn v 		next $ return True++needLocalUpdate :: ConfigKey -> Bool+needLocalUpdate (ConfigKey "annex.securehashesonly") = True+needLocalUpdate _ = False
Command/ConfigList.hs view
@@ -12,6 +12,7 @@ import Annex.Init import qualified Annex.Branch import qualified Git.Config+import Git.Types import Remote.GCrypt (coreGCryptId) import qualified CmdLine.GitAnnexShell.Fields as Fields import CmdLine.GitAnnexShell.Checks@@ -28,11 +29,12 @@ start :: CommandStart start = do 	u <- findOrGenUUID-	showConfig "annex.uuid" $ fromUUID u-	showConfig coreGCryptId =<< fromRepo (Git.Config.get coreGCryptId "")+	showConfig configkeyUUID $ fromUUID u+	showConfig coreGCryptId . fromConfigValue+		=<< fromRepo (Git.Config.get coreGCryptId mempty) 	stop   where-	showConfig k v = liftIO $ putStrLn $ k ++ "=" ++ v+	showConfig k v = liftIO $ putStrLn $ fromConfigKey k ++ "=" ++ v  {- The repository may not yet have a UUID; automatically initialize it  - when there's a git-annex branch available or if the autoinit field was
Command/ContentLocation.hs view
@@ -9,7 +9,10 @@  import Command import Annex.Content+import qualified Utility.RawFilePath as R +import qualified Data.ByteString.Char8 as B8+ cmd :: Command cmd = noCommit $ noMessages $ 	command "contentlocation" SectionPlumbing @@ -20,10 +23,10 @@ run :: () -> String -> Annex Bool run _ p = do 	let k = fromMaybe (giveup "bad key") $ deserializeKey p-	maybe (return False) (\f -> liftIO (putStrLn f) >> return True)+	maybe (return False) (\f -> liftIO (B8.putStrLn f) >> return True) 		=<< inAnnex' (pure True) Nothing check k   where-	check f = ifM (liftIO (doesFileExist f))+	check f = ifM (liftIO (R.doesPathExist f)) 		( return (Just f) 		, return Nothing 		)
Command/Copy.hs view
@@ -47,7 +47,7 @@ seek o = startConcurrency commandStages $ do 	let go = whenAnnexed $ start o 	case batchOption o of-		Batch fmt -> batchFilesMatching fmt go+		Batch fmt -> batchFilesMatching fmt (go . toRawFilePath) 		NoBatch -> withKeyOptions 			(keyOptions o) (autoMode o) 			(commandAction . Command.Move.startKey (fromToOptions o) Command.Move.RemoveNever)@@ -57,12 +57,12 @@ {- A copy is just a move that does not delete the source file.  - However, auto mode avoids unnecessary copies, and avoids getting or  - sending non-preferred content. -}-start :: CopyOptions -> FilePath -> Key -> CommandStart+start :: CopyOptions -> RawFilePath -> Key -> CommandStart start o file key = stopUnless shouldCopy $  	Command.Move.start (fromToOptions o) Command.Move.RemoveNever file key   where 	shouldCopy-		| autoMode o = want <||> numCopiesCheck file key (<)+		| autoMode o = want <||> numCopiesCheck (fromRawFilePath file) key (<) 		| otherwise = return True 	want = case fromToOptions o of 		Right (ToRemote dest) ->
Command/DiffDriver.hs view
@@ -85,12 +85,13 @@ 	check rOldFile rOldMode (\r f -> r { rOldFile = f }) req 		>>= check rNewFile rNewMode (\r f -> r { rNewFile = f })   where-	check getfile getmode setfile r = case readTreeItemType (getmode r) of+	check getfile getmode setfile r = case readTreeItemType (encodeBS' (getmode r)) of 		Just TreeSymlink -> do-			v <- getAnnexLinkTarget' (getfile r) False+			v <- getAnnexLinkTarget' (toRawFilePath (getfile r)) False 			case parseLinkTargetOrPointer =<< v of 				Nothing -> return r-				Just k -> withObjectLoc k (pure . setfile r)+				Just k -> withObjectLoc k $+					pure . setfile r . fromRawFilePath 		_ -> return r  externalDiffer :: String -> [String] -> Differ
Command/Drop.hs view
@@ -54,7 +54,7 @@ seek :: DropOptions -> CommandSeek seek o = startConcurrency transferStages $ 	case batchOption o of-		Batch fmt -> batchFilesMatching fmt go+		Batch fmt -> batchFilesMatching fmt (go . toRawFilePath) 		NoBatch -> withKeyOptions (keyOptions o) (autoMode o) 			(commandAction . startKeys o) 			(withFilesInGit (commandAction . go))@@ -62,7 +62,7 @@   where 	go = whenAnnexed $ start o -start :: DropOptions -> FilePath -> Key -> CommandStart+start :: DropOptions -> RawFilePath -> Key -> CommandStart start o file key = start' o key afile ai   where 	afile = AssociatedFile (Just file)
Command/EnableRemote.hs view
@@ -5,6 +5,8 @@  - Licensed under the GNU AGPL version 3 or higher.  -} +{-# LANGUAGE OverloadedStrings #-}+ module Command.EnableRemote where  import Command
Command/ExamineKey.hs view
@@ -22,5 +22,5 @@ run :: Maybe Utility.Format.Format -> String -> Annex Bool run format p = do 	let k = fromMaybe (giveup "bad key") $ deserializeKey p-	showFormatted format (serializeKey k) (keyVars k)+	showFormatted format (serializeKey' k) (keyVars k) 	return True
Command/Export.hs view
@@ -6,6 +6,7 @@  -}  {-# LANGUAGE TupleSections, BangPatterns #-}+{-# LANGUAGE OverloadedStrings #-}  module Command.Export where @@ -26,7 +27,6 @@ import Annex.Transfer import Annex.CatFile import Annex.FileMatcher-import Types.FileMatcher import Annex.RemoteTrackingBranch import Logs.Location import Logs.Export@@ -70,7 +70,7 @@ -- To handle renames which swap files, the exported file is first renamed -- to a stable temporary name based on the key. exportTempName :: ExportKey -> ExportLocation-exportTempName ek = mkExportLocation $ +exportTempName ek = mkExportLocation $ toRawFilePath $ 	".git-annex-tmp-content-" ++ serializeKey (asKey (ek))  seek :: ExportOptions -> CommandSeek@@ -250,7 +250,7 @@ startExport r db cvar allfilledvar ti = do 	ek <- exportKey (Git.LsTree.sha ti) 	stopUnless (notrecordedpresent ek) $-		starting ("export " ++ name r) (ActionItemOther (Just f)) $+		starting ("export " ++ name r) (ActionItemOther (Just (fromRawFilePath f))) $ 			ifM (either (const False) id <$> tryNonAsync (checkPresentExport (exportActions r) (asKey ek) loc)) 				( next $ cleanupExport r db ek loc False 				, do@@ -313,14 +313,14 @@ 	eks <- forM (filter (/= nullSha) shas) exportKey 	if null eks 		then stop-		else starting ("unexport " ++ name r) (ActionItemOther (Just f')) $+		else starting ("unexport " ++ name r) (ActionItemOther (Just (fromRawFilePath f'))) $ 			performUnexport r db eks loc   where 	loc = mkExportLocation f' 	f' = getTopFilePath f  startUnexport' :: Remote -> ExportHandle -> TopFilePath -> ExportKey -> CommandStart-startUnexport' r db f ek = starting ("unexport " ++ name r) (ActionItemOther (Just f')) $+startUnexport' r db f ek = starting ("unexport " ++ name r) (ActionItemOther (Just (fromRawFilePath f'))) $ 	performUnexport r db [ek] loc   where 	loc = mkExportLocation f'@@ -363,16 +363,15 @@ 	| otherwise = do 		ek <- exportKey sha 		let loc = exportTempName ek-		starting ("unexport " ++ name r) (ActionItemOther (Just (fromExportLocation loc))) $ do+		starting ("unexport " ++ name r) (ActionItemOther (Just (fromRawFilePath (fromExportLocation loc)))) $ do 			liftIO $ removeExportedLocation db (asKey ek) oldloc 			performUnexport r db [ek] loc   where-	oldloc = mkExportLocation oldf'-	oldf' = getTopFilePath oldf+	oldloc = mkExportLocation $ getTopFilePath oldf  startMoveToTempName :: Remote -> ExportHandle -> TopFilePath -> ExportKey -> CommandStart startMoveToTempName r db f ek = starting ("rename " ++ name r) -	(ActionItemOther $ Just $ f' ++ " -> " ++ fromExportLocation tmploc)+	(ActionItemOther $ Just $ fromRawFilePath f' ++ " -> " ++ fromRawFilePath (fromExportLocation tmploc)) 	(performRename r db ek loc tmploc)   where 	loc = mkExportLocation f'@@ -383,7 +382,7 @@ startMoveFromTempName r db ek f = do 	let tmploc = exportTempName ek 	stopUnless (liftIO $ elem tmploc <$> getExportedLocation db (asKey ek)) $-		starting ("rename " ++ name r) (ActionItemOther (Just (fromExportLocation tmploc ++ " -> " ++ f'))) $+		starting ("rename " ++ name r) (ActionItemOther (Just (fromRawFilePath (fromExportLocation tmploc) ++ " -> " ++ fromRawFilePath f'))) $ 			performRename r db ek tmploc loc   where 	loc = mkExportLocation f'
Command/Find.hs view
@@ -9,6 +9,8 @@  import Data.Default import qualified Data.Map as M+import qualified Data.ByteString as S+import qualified Data.ByteString.Char8 as S8  import Command import Annex.Content@@ -57,17 +59,17 @@ 		(commandAction . startKeys o) 		(withFilesInGit (commandAction . go)) 		=<< workTreeItems (findThese o)-	Batch fmt -> batchFilesMatching fmt go+	Batch fmt -> batchFilesMatching fmt (go . toRawFilePath)   where 	go = whenAnnexed $ start o  -- only files inAnnex are shown, unless the user has requested -- others via a limit-start :: FindOptions -> FilePath -> Key -> CommandStart+start :: FindOptions -> RawFilePath -> Key -> CommandStart start o file key = 	stopUnless (limited <||> inAnnex key) $ 		startingCustomOutput key $ do-			showFormatted (formatOption o) file $ ("file", file) : keyVars key+			showFormatted (formatOption o) file $ ("file", fromRawFilePath file) : keyVars key 			next $ return True  startKeys :: FindOptions -> (Key, ActionItem) -> CommandStart@@ -75,11 +77,11 @@ 	start o (getTopFilePath topf) key startKeys _ _ = stop -showFormatted :: Maybe Utility.Format.Format -> String -> [(String, String)] -> Annex ()+showFormatted :: Maybe Utility.Format.Format -> S.ByteString -> [(String, String)] -> Annex () showFormatted format unformatted vars = 	unlessM (showFullJSON $ JSONChunk vars) $ 		case format of-			Nothing -> liftIO $ putStrLn unformatted+			Nothing -> liftIO $ S8.putStrLn unformatted 			Just formatter -> liftIO $ putStr $ 				Utility.Format.format formatter $ 					M.fromList vars@@ -91,8 +93,8 @@ 	, ("bytesize", size show) 	, ("humansize", size $ roughSize storageUnits True) 	, ("keyname", decodeBS $ fromKey keyName key)-	, ("hashdirlower", hashDirLower def key)-	, ("hashdirmixed", hashDirMixed def key)+	, ("hashdirlower", fromRawFilePath $ hashDirLower def key)+	, ("hashdirmixed", fromRawFilePath $ hashDirMixed def key) 	, ("mtime", whenavail show $ fromKey keyMtime key) 	]   where
Command/Fix.hs view
@@ -17,6 +17,7 @@ import Annex.Perms import qualified Annex.Queue import qualified Database.Keys+import qualified Utility.RawFilePath as R  #if ! defined(mingw32_HOST_OS) import Utility.Touch@@ -37,13 +38,14 @@  data FixWhat = FixSymlinks | FixAll -start :: FixWhat -> FilePath -> Key -> CommandStart+start :: FixWhat -> RawFilePath -> Key -> CommandStart start fixwhat file key = do-	currlink <- liftIO $ catchMaybeIO $ readSymbolicLink file-	wantlink <- calcRepo $ gitAnnexLink file key+	currlink <- liftIO $ catchMaybeIO $ R.readSymbolicLink file+	wantlink <- calcRepo $ gitAnnexLink (fromRawFilePath file) key 	case currlink of 		Just l-			| l /= wantlink -> fixby $ fixSymlink file wantlink+			| l /= toRawFilePath wantlink -> fixby $+				fixSymlink (fromRawFilePath file) wantlink 			| otherwise -> stop 		Nothing -> case fixwhat of 			FixAll -> fixthin@@ -51,11 +53,11 @@   where 	fixby = starting "fix" (mkActionItem (key, file)) 	fixthin = do-		obj <- calcRepo $ gitAnnexLocation key+		obj <- calcRepo (gitAnnexLocation key) 		stopUnless (isUnmodified key file <&&> isUnmodified key obj) $ do 			thin <- annexThin <$> Annex.getGitConfig-			fs <- liftIO $ catchMaybeIO $ getFileStatus file-			os <- liftIO $ catchMaybeIO $ getFileStatus obj+			fs <- liftIO $ catchMaybeIO $ R.getFileStatus file+			os <- liftIO $ catchMaybeIO $ R.getFileStatus obj 			case (linkCount <$> fs, linkCount <$> os, thin) of 				(Just 1, Just 1, True) -> 					fixby $ makeHardLink file key@@ -63,21 +65,22 @@ 					fixby $ breakHardLink file key obj 				_ -> stop -breakHardLink :: FilePath -> Key -> FilePath -> CommandPerform+breakHardLink :: RawFilePath -> Key -> RawFilePath -> CommandPerform breakHardLink file key obj = do-	replaceFile file $ \tmp -> do-		mode <- liftIO $ catchMaybeIO $ fileMode <$> getFileStatus file-		unlessM (checkedCopyFile key obj tmp mode) $+	replaceFile (fromRawFilePath file) $ \tmp -> do+		mode <- liftIO $ catchMaybeIO $ fileMode <$> R.getFileStatus file+		let obj' = fromRawFilePath obj+		unlessM (checkedCopyFile key obj' tmp mode) $ 			error "unable to break hard link" 		thawContent tmp-		modifyContent obj $ freezeContent obj+		modifyContent obj' $ freezeContent obj' 	Database.Keys.storeInodeCaches key [file] 	next $ return True -makeHardLink :: FilePath -> Key -> CommandPerform+makeHardLink :: RawFilePath -> Key -> CommandPerform makeHardLink file key = do-	replaceFile file $ \tmp -> do-		mode <- liftIO $ catchMaybeIO $ fileMode <$> getFileStatus file+	replaceFile (fromRawFilePath file) $ \tmp -> do+		mode <- liftIO $ catchMaybeIO $ fileMode <$> R.getFileStatus file 		linkFromAnnex key tmp mode >>= \case 			LinkAnnexFailed -> error "unable to make hard link" 			_ -> noop
Command/FromKey.hs view
@@ -51,7 +51,7 @@ 		in if not (null keyname) && not (null file) 			then Right $ go file (keyOpt keyname) 			else Left "Expected pairs of key and filename"-	go file key = starting "fromkey" (mkActionItem (key, file)) $+	go file key = starting "fromkey" (mkActionItem (key, toRawFilePath file)) $ 		perform key file  start :: Bool -> (String, FilePath) -> CommandStart@@ -61,7 +61,7 @@ 		inbackend <- inAnnex key 		unless inbackend $ giveup $ 			"key ("++ keyname ++") is not present in backend (use --force to override this sanity check)"-	starting "fromkey" (mkActionItem (key, file)) $+	starting "fromkey" (mkActionItem (key, toRawFilePath file)) $ 		perform key file  -- From user input to a Key.@@ -80,7 +80,7 @@ 		Nothing -> giveup $ "bad key/url " ++ s  perform :: Key -> FilePath -> CommandPerform-perform key file = lookupFileNotHidden file >>= \case+perform key file = lookupFileNotHidden (toRawFilePath file) >>= \case 	Nothing -> ifM (liftIO $ doesFileExist file) 		( hasothercontent 		, do
Command/Fsck.hs view
@@ -35,6 +35,7 @@ import Types.CleanupActions import Types.Key import Types.ActionItem+import qualified Utility.RawFilePath as R  import Data.Time.Clock.POSIX import System.Posix.Types (EpochTime)@@ -102,11 +103,11 @@ 	whenM ((==) DeadTrusted <$> lookupTrust u) $ 		earlyWarning "Warning: Fscking a repository that is currently marked as dead." -start :: Maybe Remote -> Incremental -> FilePath -> Key -> CommandStart-start from inc file key = Backend.getBackend file key >>= \case+start :: Maybe Remote -> Incremental -> RawFilePath -> Key -> CommandStart+start from inc file key = Backend.getBackend (fromRawFilePath file) key >>= \case 	Nothing -> stop 	Just backend -> do-		numcopies <- getFileNumCopies file+		numcopies <- getFileNumCopies (fromRawFilePath file) 		case from of 			Nothing -> go $ perform key file backend numcopies 			Just r -> go $ performRemote key afile backend numcopies r@@ -114,9 +115,9 @@ 	go = runFsck inc (mkActionItem (key, afile)) key 	afile = AssociatedFile (Just file) -perform :: Key -> FilePath -> Backend -> NumCopies -> Annex Bool+perform :: Key -> RawFilePath -> Backend -> NumCopies -> Annex Bool perform key file backend numcopies = do-	keystatus <- getKeyFileStatus key file+	keystatus <- getKeyFileStatus key (fromRawFilePath file) 	check 		-- order matters 		[ fixLink key file@@ -163,7 +164,7 @@ 		pid <- liftIO getPID 		t <- fromRepo gitAnnexTmpObjectDir 		createAnnexDirectory t-		let tmp = t </> "fsck" ++ show pid ++ "." ++ keyFile key+		let tmp = t </> "fsck" ++ show pid ++ "." ++ fromRawFilePath (keyFile key) 		let cleanup = liftIO $ catchIO (removeFile tmp) (const noop) 		cleanup 		cleanup `after` a tmp@@ -203,18 +204,18 @@ check cs = and <$> sequence cs  {- Checks that symlinks points correctly to the annexed content. -}-fixLink :: Key -> FilePath -> Annex Bool+fixLink :: Key -> RawFilePath -> Annex Bool fixLink key file = do-	want <- calcRepo $ gitAnnexLink file key+	want <- calcRepo $ gitAnnexLink (fromRawFilePath file) key 	have <- getAnnexLinkTarget file 	maybe noop (go want) have 	return True   where 	go want have-		| want /= fromInternalGitPath (fromRawFilePath have) = do+		| want /= fromRawFilePath (fromInternalGitPath have) = do 			showNote "fixing link"-			liftIO $ createDirectoryIfMissing True (parentDir file)-			liftIO $ removeFile file+			liftIO $ createDirectoryIfMissing True (parentDir (fromRawFilePath file))+			liftIO $ removeFile (fromRawFilePath file) 			addAnnexLink want file 		| otherwise = noop @@ -222,7 +223,7 @@  - in this repository only. -} verifyLocationLog :: Key -> KeyStatus -> ActionItem -> Annex Bool verifyLocationLog key keystatus ai = do-	obj <- calcRepo $ gitAnnexLocation key+	obj <- fromRawFilePath <$> calcRepo (gitAnnexLocation key) 	present <- if isKeyUnlockedThin keystatus 		then liftIO (doesFileExist obj) 		else inAnnex key@@ -267,7 +268,7 @@ 			fix InfoMissing 			warning $ 				"** Based on the location log, " ++-				actionItemDesc ai +++				decodeBS' (actionItemDesc ai) ++ 				"\n** was expected to be present, " ++ 				"but its content is missing." 			return False@@ -302,14 +303,14 @@ 					missingrequired <- Remote.prettyPrintUUIDs "missingrequired" missinglocs 					warning $ 						"** Required content " ++-						actionItemDesc ai +++						decodeBS' (actionItemDesc ai) ++ 						" is missing from these repositories:\n" ++ 						missingrequired 					return False verifyRequiredContent _ _ = return True  {- Verifies the associated file records. -}-verifyAssociatedFiles :: Key -> KeyStatus -> FilePath -> Annex Bool+verifyAssociatedFiles :: Key -> KeyStatus -> RawFilePath -> Annex Bool verifyAssociatedFiles key keystatus file = do 	when (isKeyUnlockedThin keystatus) $ do 		f <- inRepo $ toTopFilePath file@@ -318,7 +319,7 @@ 			Database.Keys.addAssociatedFile key f 	return True -verifyWorkTree :: Key -> FilePath -> Annex Bool+verifyWorkTree :: Key -> RawFilePath -> Annex Bool verifyWorkTree key file = do 	{- Make sure that a pointer file is replaced with its content, 	 - when the content is available. -}@@ -326,12 +327,12 @@ 	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+			replaceFile (fromRawFilePath file) $ \tmp -> do+				mode <- liftIO $ catchMaybeIO $ fileMode <$> R.getFileStatus file 				ifM (annexThin <$> Annex.getGitConfig) 					( void $ linkFromAnnex key tmp mode 					, do-						obj <- calcRepo $ gitAnnexLocation key+						obj <- fromRawFilePath <$> calcRepo (gitAnnexLocation key) 						void $ checkedCopyFile key obj tmp mode 						thawContent tmp 					)@@ -348,8 +349,8 @@ checkKeySize _ KeyUnlockedThin _ = return True checkKeySize key _ ai = do 	file <- calcRepo $ gitAnnexLocation key-	ifM (liftIO $ doesFileExist file)-		( checkKeySizeOr badContent key file ai+	ifM (liftIO $ R.doesPathExist file)+		( checkKeySizeOr badContent key (fromRawFilePath file) ai 		, return True 		) @@ -375,7 +376,7 @@ 	badsize a b = do 		msg <- bad key 		warning $ concat-			[ actionItemDesc ai+			[ decodeBS' (actionItemDesc ai) 			, ": Bad file size (" 			, compareSizes storageUnits True a b 			, "); "@@ -393,11 +394,11 @@ 	case Types.Backend.canUpgradeKey backend of 		Just a | a key -> do 			warning $ concat-				[ actionItemDesc ai+				[ decodeBS' (actionItemDesc ai) 				, ": Can be upgraded to an improved key format. " 				, "You can do so by running: git annex migrate --backend=" 				, decodeBS (formatKeyVariety (fromKey keyVariety key)) ++ " "-				, file+				, decodeBS' file 				] 			return True 		_ -> return True@@ -416,10 +417,10 @@  -} checkBackend :: Backend -> Key -> KeyStatus -> AssociatedFile -> Annex Bool checkBackend backend key keystatus afile = do-	content <- calcRepo $ gitAnnexLocation key+	content <- calcRepo (gitAnnexLocation key) 	ifM (pure (isKeyUnlockedThin keystatus) <&&> (not <$> isUnmodified key content)) 		( nocheck-		, checkBackendOr badContent backend key content ai+		, checkBackendOr badContent backend key (fromRawFilePath content) ai 		)   where 	nocheck = return True@@ -448,7 +449,7 @@ 					unless ok $ do 						msg <- bad key 						warning $ concat-							[ actionItemDesc ai+							[ decodeBS' (actionItemDesc ai) 							, ": Bad file content; " 							, msg 							]@@ -460,7 +461,7 @@ checkKeyNumCopies key afile numcopies = do 	let (desc, hasafile) = case afile of 		AssociatedFile Nothing -> (serializeKey key, False)-		AssociatedFile (Just af) -> (af, True)+		AssociatedFile (Just af) -> (fromRawFilePath af, True) 	locs <- loggedLocations key 	(untrustedlocations, otherlocations) <- trustPartition UnTrusted locs 	(deadlocations, safelocations) <- trustPartition DeadTrusted otherlocations@@ -515,7 +516,7 @@ badContentRemote :: Remote -> FilePath -> Key -> Annex String badContentRemote remote localcopy key = do 	bad <- fromRepo gitAnnexBadDir-	let destbad = bad </> keyFile key+	let destbad = bad </> fromRawFilePath (keyFile key) 	movedbad <- ifM (inAnnex key <||> liftIO (doesFileExist destbad)) 		( return False 		, do@@ -669,8 +670,8 @@ getKeyStatus :: Key -> Annex KeyStatus getKeyStatus key = catchDefaultIO KeyMissing $ do 	afs <- not . null <$> Database.Keys.getAssociatedFiles key-	obj <- calcRepo $ gitAnnexLocation key-	multilink <- ((> 1) . linkCount <$> liftIO (getFileStatus obj))+	obj <- calcRepo (gitAnnexLocation key)+	multilink <- ((> 1) . linkCount <$> liftIO (R.getFileStatus obj)) 	return $ if multilink && afs 		then KeyUnlockedThin 		else KeyPresent@@ -680,7 +681,7 @@ 	s <- getKeyStatus key 	case s of 		KeyUnlockedThin -> catchDefaultIO KeyUnlockedThin $-			ifM (isJust <$> isAnnexLink file)+			ifM (isJust <$> isAnnexLink (toRawFilePath file)) 				( return KeyLockedThin 				, return KeyUnlockedThin 				)
Command/FuzzTest.hs view
@@ -5,6 +5,8 @@  - Licensed under the GNU AGPL version 3 or higher.  -} +{-# LANGUAGE OverloadedStrings #-}+ module Command.FuzzTest where  import Command@@ -13,6 +15,7 @@ import Config import Utility.ThreadScheduler import Utility.DiskFree+import Git.Types (fromConfigKey)  import Data.Time.Clock import System.Random (getStdRandom, random, randomR)@@ -32,25 +35,23 @@ start = do 	guardTest 	logf <- fromRepo gitAnnexFuzzTestLogFile-	showStart "fuzztest" logf+	showStart "fuzztest" (toRawFilePath logf) 	logh <- liftIO $ openFile logf WriteMode 	void $ forever $ fuzz logh 	stop  guardTest :: Annex ()-guardTest = unlessM (fromMaybe False . Git.Config.isTrue <$> getConfig key "") $+guardTest = unlessM (fromMaybe False . Git.Config.isTrueFalse' <$> getConfig key mempty) $ 	giveup $ unlines 		[ "Running fuzz tests *writes* to and *deletes* files in" 		, "this repository, and pushes those changes to other" 		, "repositories! This is a developer tool, not something" 		, "to play with." 		, ""-		, "Refusing to run fuzz tests, since " ++ keyname ++ " is not set!"+		, "Refusing to run fuzz tests, since " ++ fromConfigKey key ++ " is not set!" 		]   where 	key = annexConfig "eat-my-repository"-	(ConfigKey keyname) = key-  fuzz :: Handle -> Annex () fuzz logh = do
Command/Get.hs view
@@ -42,19 +42,19 @@ 	from <- maybe (pure Nothing) (Just <$$> getParsed) (getFrom o) 	let go = whenAnnexed $ start o from 	case batchOption o of-		Batch fmt -> batchFilesMatching fmt go+		Batch fmt -> batchFilesMatching fmt (go . toRawFilePath) 		NoBatch -> withKeyOptions (keyOptions o) (autoMode o) 			(commandAction . startKeys from) 			(withFilesInGit (commandAction . go)) 			=<< workTreeItems (getFiles o) -start :: GetOptions -> Maybe Remote -> FilePath -> Key -> CommandStart+start :: GetOptions -> Maybe Remote -> RawFilePath -> Key -> CommandStart start o from file key = start' expensivecheck from key afile ai   where 	afile = AssociatedFile (Just file) 	ai = mkActionItem (key, afile) 	expensivecheck-		| autoMode o = numCopiesCheck file key (<)+		| autoMode o = numCopiesCheck (fromRawFilePath file) key (<) 			<||> wantGet False (Just key) afile 		| otherwise = return True 
Command/Import.hs view
@@ -97,12 +97,13 @@  seek :: ImportOptions -> CommandSeek seek o@(LocalImportOptions {}) = startConcurrency commandStages $ do-	repopath <- liftIO . absPath =<< fromRepo Git.repoPath+	repopath <- liftIO . absPath . fromRawFilePath =<< fromRepo Git.repoPath 	inrepops <- liftIO $ filter (dirContains repopath) <$> mapM absPath (importFiles o) 	unless (null inrepops) $ do 		giveup $ "cannot import files from inside the working tree (use git annex add instead): " ++ unwords inrepops 	largematcher <- largeFilesMatcher-	(commandAction . startLocal largematcher (duplicateMode o))+	addunlockedmatcher <- addUnlockedMatcher+	(commandAction . startLocal addunlockedmatcher largematcher (duplicateMode o)) 		`withPathContents` importFiles o seek o@(RemoteImportOptions {}) = startConcurrency commandStages $ do 	r <- getParsed (importFromRemote o)@@ -110,14 +111,14 @@ 		giveup "That remote does not support imports." 	subdir <- maybe 		(pure Nothing)-		(Just <$$> inRepo . toTopFilePath)+		(Just <$$> inRepo . toTopFilePath . toRawFilePath) 		(importToSubDir o) 	seekRemote r (importToBranch o) subdir -startLocal :: GetFileMatcher -> DuplicateMode -> (FilePath, FilePath) -> CommandStart-startLocal largematcher mode (srcfile, destfile) =+startLocal :: AddUnlockedMatcher -> GetFileMatcher -> DuplicateMode -> (FilePath, FilePath) -> CommandStart+startLocal addunlockedmatcher largematcher mode (srcfile, destfile) = 	ifM (liftIO $ isRegularFile <$> getSymbolicLinkStatus srcfile)-		( starting "import" (ActionItemWorkTreeFile destfile)+		( starting "import" (ActionItemWorkTreeFile (toRawFilePath destfile)) 			pickaction 		, stop 		)@@ -181,7 +182,7 @@ 		-- weakly the same as the origianlly 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+		newcache <- withTSDelta $ liftIO . genInodeCache (toRawFilePath destfile) 		let unchanged = case (newcache, inodeCache (keySource ld)) of 			(_, Nothing) -> True 			(Just newc, Just c) | compareWeak c newc -> True@@ -202,13 +203,17 @@ 				>>= maybe 					stop 					(\addedk -> next $ Command.Add.cleanup addedk True)-			, next $ Command.Add.addSmall destfile +			, next $ Command.Add.addSmall $ toRawFilePath destfile  			) 	notoverwriting why = do 		warning $ "not overwriting existing " ++ destfile ++ " " ++ why 		stop 	lockdown a = do-		lockingfile <- not <$> addUnlocked+		let mi = MatchingFile $ FileInfo+			{ currFile = toRawFilePath srcfile+			, matchFile = toRawFilePath destfile+			}+		lockingfile <- not <$> addUnlocked addunlockedmatcher mi 		-- Minimal lock down with no hard linking so nothing 		-- has to be done to clean up from it. 		let cfg = LockDownConfig
Command/ImportFeed.hs view
@@ -38,6 +38,7 @@ import Types.MetaData import Logs.MetaData import Annex.MetaData+import Annex.FileMatcher import Command.AddUrl (addWorkTree)  cmd :: Command@@ -62,12 +63,13 @@  seek :: ImportFeedOptions -> CommandSeek seek o = do+	addunlockedmatcher <- addUnlockedMatcher 	cache <- getCache (templateOption o)-	forM_ (feedUrls o) (getFeed o cache)+	forM_ (feedUrls o) (getFeed addunlockedmatcher o cache) -getFeed :: ImportFeedOptions -> Cache -> URLString -> CommandSeek-getFeed opts cache url = do-	showStart "importfeed" url+getFeed :: AddUnlockedMatcher -> ImportFeedOptions -> Cache -> URLString -> CommandSeek+getFeed addunlockedmatcher opts cache url = do+	showStart' "importfeed" (Just url) 	downloadFeed url >>= \case 		Nothing -> showEndResult =<< feedProblem url 			"downloading the feed failed"@@ -77,7 +79,7 @@ 				[] -> debugfeedcontent feedcontent "bad feed content; no enclosures to download" 				l -> do 					showEndOk-					ifM (and <$> mapM (performDownload opts cache) l)+					ifM (and <$> mapM (performDownload addunlockedmatcher opts cache) l) 						( clearFeedProblem url 						, void $ feedProblem url  							"problem downloading some item(s) from feed"@@ -153,8 +155,8 @@ 			, return Nothing 			) -performDownload :: ImportFeedOptions -> Cache -> ToDownload -> Annex Bool-performDownload opts cache todownload = case location todownload of+performDownload :: AddUnlockedMatcher -> ImportFeedOptions -> Cache -> ToDownload -> Annex Bool+performDownload addunlockedmatcher opts cache todownload = case location todownload of 	Enclosure url -> checkknown url $ 		rundownload url (takeWhile (/= '?') $ takeExtension url) $ \f -> do 			r <- Remote.claimingUrl url@@ -171,7 +173,7 @@ 						-- don't use youtube-dl 						, rawOption = True 						}-					maybeToList <$> addUrlFile dlopts url urlinfo f+					maybeToList <$> addUrlFile addunlockedmatcher dlopts url urlinfo f 				else do 					res <- tryNonAsync $ maybe 						(error $ "unable to checkUrl of " ++ Remote.name r)@@ -181,10 +183,10 @@ 						Left _ -> return [] 						Right (UrlContents sz _) -> 							maybeToList <$>-								downloadRemoteFile r (downloadOptions opts) url f sz+								downloadRemoteFile addunlockedmatcher r (downloadOptions opts) url f sz 						Right (UrlMulti l) -> do 							kl <- forM l $ \(url', sz, subf) ->-								downloadRemoteFile r (downloadOptions opts) url' (f </> fromSafeFilePath subf) sz+								downloadRemoteFile addunlockedmatcher r (downloadOptions opts) url' (f </> fromSafeFilePath subf) sz 							return $ if all isJust kl 								then catMaybes kl 								else []@@ -222,7 +224,7 @@ 		case dest of 			Nothing -> return True 			Just f -> do-				showStart "addurl" url+				showStart' "addurl" (Just url) 				ks <- getter f 				if null ks 					then do@@ -244,7 +246,7 @@ 	 - to be re-downloaded. -} 	makeunique url n file = ifM alreadyexists 		( ifM forced-			( ifAnnexed f checksameurl tryanother+			( ifAnnexed (toRawFilePath f) checksameurl tryanother 			, tryanother 			) 		, return $ Just f@@ -273,7 +275,7 @@ 							[] -> ".m" 							s -> s 						ok <- rundownload linkurl ext $ \f -> do-							addWorkTree webUUID mediaurl f mediakey (Just mediafile)+							addWorkTree addunlockedmatcher webUUID mediaurl f mediakey (Just mediafile) 							return [mediakey] 						return (Just ok) 					-- youtude-dl didn't support it, so@@ -285,16 +287,16 @@ 						return Nothing 			return (fromMaybe False r) 	  where-		downloadlink = performDownload opts cache todownload+		downloadlink = performDownload addunlockedmatcher opts cache todownload 			{ location = Enclosure linkurl }  	addmediafast linkurl mediaurl mediakey = 		ifM (pure (not (rawOption (downloadOptions opts))) 		     <&&> youtubeDlSupported linkurl) 			( rundownload linkurl ".m" $ \f -> do-				addWorkTree webUUID mediaurl f mediakey Nothing+				addWorkTree addunlockedmatcher webUUID mediaurl f mediakey Nothing 				return [mediakey]-			, performDownload opts cache todownload+			, performDownload addunlockedmatcher opts cache todownload 				{ location = Enclosure linkurl } 			) 
Command/Info.hs view
@@ -152,7 +152,7 @@ 				v' <- Remote.nameToUUID' p 				case v' of 					Right u -> uuidInfo o u-					Left _ -> ifAnnexed p +					Left _ -> ifAnnexed (toRawFilePath p) 						(fileInfo o p) 						(treeishInfo o p) 	)@@ -161,7 +161,7 @@  noInfo :: String -> Annex () noInfo s = do-	showStart "info" s+	showStart "info" (encodeBS' s) 	showNote $ "not a directory or an annexed file or a treeish or a remote or a uuid" 	showEndFail @@ -311,8 +311,8 @@ showStat s = maybe noop calc =<< s   where 	calc (desc, a) = do-		(lift . showHeader) desc-		lift . showRaw =<< a+		(lift . showHeader . encodeBS') desc+		lift . showRaw . encodeBS' =<< a  repo_list :: TrustLevel -> Stat repo_list level = stat n $ nojson $ lift $ do@@ -435,7 +435,7 @@ 	desc = "transfers in progress" 	line uuidmap t i = unwords 		[ formatDirection (transferDirection t) ++ "ing"-		, actionItemDesc $ mkActionItem+		, fromRawFilePath $ actionItemDesc $ mkActionItem 			(transferKey t, associatedFile i) 		, if transferDirection t == Upload then "to" else "from" 		, maybe (fromUUID $ transferUUID t) Remote.name $@@ -444,7 +444,7 @@ 	jsonify t i = object $ map (\(k, v) -> (packString k, v)) $ 		[ ("transfer", toJSON' (formatDirection (transferDirection t))) 		, ("key", toJSON' (transferKey t))-		, ("file", toJSON' afile)+		, ("file", toJSON' (fromRawFilePath <$> afile)) 		, ("remote", toJSON' (fromUUID (transferUUID t) :: String)) 		] 	  where@@ -454,7 +454,7 @@ disk_size = simpleStat "available local disk space" $ 	calcfree 		<$> (lift $ annexDiskReserve <$> Annex.getGitConfig)-		<*> (lift $ inRepo $ getDiskFree . gitAnnexDir)+		<*> (lift $ inRepo $ getDiskFree . fromRawFilePath . gitAnnexDir) 		<*> mkSizer   where 	calcfree reserve (Just have) sizer = unwords@@ -577,7 +577,7 @@ 					then return (numcopiesstats, repodata) 					else do 						locs <- Remote.keyLocations key-						nc <- updateNumCopiesStats file numcopiesstats locs+						nc <- updateNumCopiesStats (fromRawFilePath file) numcopiesstats locs 						return (nc, updateRepoData key locs repodata) 				return $! (presentdata', referenceddata', numcopiesstats', repodata') 			, return vs@@ -674,7 +674,7 @@ 	keysizes keys = do 		dir <- lift $ fromRepo dirspec 		liftIO $ forM keys $ \k -> catchDefaultIO 0 $-			getFileSize (dir </> keyFile k)+			getFileSize (dir </> fromRawFilePath (keyFile k))  aside :: String -> String aside s = " (" ++ s ++ ")"
Command/InitRemote.hs view
@@ -5,6 +5,8 @@  - Licensed under the GNU AGPL version 3 or higher.  -} +{-# LANGUAGE OverloadedStrings #-}+ module Command.InitRemote where  import qualified Data.Map as M
Command/Inprogress.hs view
@@ -42,7 +42,7 @@ 				(commandAction . (whenAnnexed (start s))) 				=<< workTreeItems (inprogressFiles o) -start :: S.Set Key -> FilePath -> Key -> CommandStart+start :: S.Set Key -> RawFilePath -> Key -> CommandStart start s _file k 	| S.member k s = start' k 	| otherwise = stop
Command/List.hs view
@@ -72,7 +72,7 @@ printHeader :: [(UUID, RemoteName, TrustLevel)] -> Annex () printHeader l = liftIO $ putStrLn $ lheader $ map (\(_, n, t) -> (n, t)) l -start :: [(UUID, RemoteName, TrustLevel)] -> FilePath -> Key -> CommandStart+start :: [(UUID, RemoteName, TrustLevel)] -> RawFilePath -> Key -> CommandStart start l file key = do 	ls <- S.fromList <$> keyLocations key 	liftIO $ putStrLn $ format (map (\(u, _, t) -> (t, S.member u ls)) l) file@@ -88,8 +88,8 @@ 	trust UnTrusted = " (untrusted)" 	trust _ = "" -format :: [(TrustLevel, Present)] -> FilePath -> String-format remotes file = thereMap ++ " " ++ file+format :: [(TrustLevel, Present)] -> RawFilePath -> String+format remotes file = thereMap ++ " " ++ fromRawFilePath file   where  	thereMap = concatMap there remotes 	there (UnTrusted, True) = "x"
Command/Lock.hs view
@@ -20,6 +20,7 @@ import Annex.Ingest import Logs.Location import Git.FilePath+import qualified Utility.RawFilePath as R 	 cmd :: Command cmd = withGlobalOptions [jsonOptions, annexedMatchingOptions] $@@ -32,7 +33,7 @@ 	l <- workTreeItems ps 	withFilesInGit (commandAction . (whenAnnexed startNew)) l -startNew :: FilePath -> Key -> CommandStart+startNew :: RawFilePath -> Key -> CommandStart startNew file key = ifM (isJust <$> isAnnexLink file) 	( stop 	, starting "lock" (mkActionItem (key, file)) $@@ -43,7 +44,7 @@ 		| key' == key = cont 		| otherwise = errorModified 	go Nothing = -		ifM (isUnmodified key file) +		ifM (isUnmodified key file) 			( cont 			, ifM (Annex.getState Annex.force) 				( cont@@ -52,28 +53,29 @@ 			) 	cont = performNew file key -performNew :: FilePath -> Key -> CommandPerform+performNew :: RawFilePath -> Key -> CommandPerform performNew file key = do 	lockdown =<< calcRepo (gitAnnexLocation key)-	addLink file key+	addLink (fromRawFilePath file) key 		=<< withTSDelta (liftIO . genInodeCache file) 	next $ cleanupNew file key   where 	lockdown obj = do 		ifM (isUnmodified key obj) 			( breakhardlink obj-			, repopulate obj+			, repopulate (fromRawFilePath obj) 			)-		whenM (liftIO $ doesFileExist obj) $-			freezeContent obj+		whenM (liftIO $ R.doesPathExist obj) $+			freezeContent $ fromRawFilePath obj  	-- It's ok if the file is hard linked to obj, but if some other 	-- associated file is, we need to break that link to lock down obj.-	breakhardlink obj = whenM (catchBoolIO $ (> 1) . linkCount <$> liftIO (getFileStatus obj)) $ do+	breakhardlink obj = whenM (catchBoolIO $ (> 1) . linkCount <$> liftIO (R.getFileStatus obj)) $ do 		mfc <- withTSDelta (liftIO . genInodeCache file) 		unlessM (sameInodeCache obj (maybeToList mfc)) $ do-			modifyContent obj $ replaceFile obj $ \tmp -> do-				unlessM (checkedCopyFile key obj tmp Nothing) $+			let obj' = fromRawFilePath obj+			modifyContent obj' $ replaceFile obj' $ \tmp -> do+				unlessM (checkedCopyFile key obj' tmp Nothing) $ 					giveup "unable to lock file" 			Database.Keys.storeInodeCaches key [obj] @@ -86,27 +88,27 @@ 		liftIO $ nukeFile obj 		case mfile of 			Just unmodified ->-				unlessM (checkedCopyFile key unmodified obj Nothing)+				unlessM (checkedCopyFile key (fromRawFilePath unmodified) obj Nothing) 					lostcontent 			Nothing -> lostcontent  	lostcontent = logStatus key InfoMissing -cleanupNew :: FilePath -> Key -> CommandCleanup+cleanupNew :: RawFilePath -> Key -> CommandCleanup cleanupNew file key = do 	Database.Keys.removeAssociatedFile key =<< inRepo (toTopFilePath file) 	return True -startOld :: FilePath -> CommandStart+startOld :: RawFilePath -> CommandStart startOld file = do 	unlessM (Annex.getState Annex.force) 		errorModified 	starting "lock" (ActionItemWorkTreeFile file) $ 		performOld file -performOld :: FilePath -> CommandPerform+performOld :: RawFilePath -> CommandPerform performOld file = do-	Annex.Queue.addCommand "checkout" [Param "--"] [file]+	Annex.Queue.addCommand "checkout" [Param "--"] [fromRawFilePath file] 	next $ return True  errorModified :: a
Command/Log.hs view
@@ -92,10 +92,10 @@ 		([], True) -> commandAction (startAll o outputter) 		(_, True) -> giveup "Cannot specify both files and --all" -start :: LogOptions -> (FilePath -> Outputter) -> FilePath -> Key -> CommandStart+start :: LogOptions -> (FilePath -> Outputter) -> RawFilePath -> Key -> CommandStart start o outputter file key = do 	(changes, cleanup) <- getKeyLog key (passthruOptions o)-	showLogIncremental (outputter file) changes+	showLogIncremental (outputter (fromRawFilePath file)) changes 	void $ liftIO cleanup 	stop @@ -199,9 +199,9 @@ getKeyLog :: Key -> [CommandParam] -> Annex ([RefChange], IO Bool) getKeyLog key os = do 	top <- fromRepo Git.repoPath-	p <- liftIO $ relPathCwdToFile top+	p <- liftIO $ relPathCwdToFile $ fromRawFilePath top 	config <- Annex.getGitConfig-	let logfile = p </> locationLogFile config key+	let logfile = p </> fromRawFilePath (locationLogFile config key) 	getGitLog [logfile] (Param "--remove-empty" : os)  {- Streams the git log for all git-annex branch changes. -}@@ -220,7 +220,7 @@ 		[ Param $ Git.fromRef Annex.Branch.fullname 		, Param "--" 		] ++ map Param fs-	return (parseGitRawLog ls, cleanup)+	return (parseGitRawLog (map decodeBL' ls), cleanup)  -- Parses chunked git log --raw output, which looks something like: --@@ -250,7 +250,7 @@ 			(tss, cl') -> (parseTimeStamp tss, cl') 	  	mrc = do 			(old, new) <- parseRawChangeLine cl-			key <- locationLogFileKey c2+			key <- locationLogFileKey (toRawFilePath c2) 			return $ RefChange 				{ changetime = ts 				, oldref = old
Command/LookupKey.hs view
@@ -29,11 +29,12 @@  -- To support absolute filenames, pass through git ls-files. -- But, this plumbing command does not recurse through directories.-seekSingleGitFile :: FilePath -> Annex (Maybe FilePath)+seekSingleGitFile :: FilePath -> Annex (Maybe RawFilePath) seekSingleGitFile file = do-	(l, cleanup) <- inRepo (Git.LsFiles.inRepo [file])+	(l, cleanup) <- inRepo (Git.LsFiles.inRepo [toRawFilePath file]) 	r <- case l of-		(f:[]) | takeFileName f == takeFileName file -> return (Just f)+		(f:[]) | takeFileName (fromRawFilePath f) == takeFileName file ->+			return (Just f) 		_ -> return Nothing 	void $ liftIO cleanup 	return r
Command/Map.hs view
@@ -46,7 +46,9 @@ 	umap <- uuidDescMap 	trustmap <- trustMapLoad 		-	file <- (</>) <$> fromRepo gitAnnexDir <*> pure "map.dot"+	file <- (</>)+		<$> fromRepo (fromRawFilePath . gitAnnexDir)+		<*> pure "map.dot"  	liftIO $ writeFile file (drawMap rs trustmap umap) 	next $@@ -176,7 +178,8 @@ 	| Git.repoIsUrl reference = return $ Git.Construct.localToUrl reference r 	| Git.repoIsUrl r = return r 	| otherwise = liftIO $ do-		r' <- Git.Construct.fromAbsPath =<< absPath (Git.repoPath r)+		r' <- Git.Construct.fromAbsPath+			=<< absPath (fromRawFilePath (Git.repoPath r)) 		r'' <- safely $ flip Annex.eval Annex.gitRepo =<< Annex.new r' 		return (fromMaybe r' r'') @@ -234,7 +237,7 @@ 	  where 		remotecmd = "sh -c " ++ shellEscape 			(cddir ++ " && " ++ "git config --null --list")-		dir = Git.repoPath r+		dir = fromRawFilePath $ Git.repoPath r 		cddir 			| "/~" `isPrefixOf` dir = 				let (userhome, reldir) = span (/= '/') (drop 1 dir)
Command/MatchExpression.hs view
@@ -9,7 +9,6 @@  import Command import Annex.FileMatcher-import Types.FileMatcher import Utility.DataUnits import Utility.Matcher import Annex.UUID@@ -75,7 +74,7 @@ seek :: MatchExpressionOptions -> CommandSeek seek o = do 	parser <- if largeFilesExpression o-		then mkLargeFilesParser+		then mkMatchExpressionParser 		else do 			u <- getUUID 			pure $ preferredContentParser $ preferredContentTokens $ PCD
Command/MetaData.hs view
@@ -92,7 +92,7 @@ 			) 		_ -> giveup "--batch is currently only supported in --json mode" -start :: VectorClock -> MetaDataOptions -> FilePath -> Key -> CommandStart+start :: VectorClock -> MetaDataOptions -> RawFilePath -> Key -> CommandStart start c o file k = startKeys c o (k, mkActionItem (k, afile))   where 	afile = AssociatedFile (Just file)@@ -147,7 +147,7 @@ fieldsField :: T.Text fieldsField = T.pack "fields" -parseJSONInput :: String -> Either String (Either FilePath Key, MetaData)+parseJSONInput :: String -> Either String (Either RawFilePath Key, MetaData) parseJSONInput i = do 	v <- eitherDecode (BU.fromString i) 	let m = case itemAdded v of@@ -155,16 +155,16 @@ 		Just (MetaDataFields m') -> m' 	case (itemKey v, itemFile v) of 		(Just k, _) -> Right (Right k, m)-		(Nothing, Just f) -> Right (Left f, m)+		(Nothing, Just f) -> Right (Left (toRawFilePath f), m) 		(Nothing, Nothing) -> Left "JSON input is missing either file or key" -startBatch :: (Either FilePath Key, MetaData) -> CommandStart+startBatch :: (Either RawFilePath Key, MetaData) -> CommandStart startBatch (i, (MetaData m)) = case i of 	Left f -> do 		mk <- lookupFile f 		case mk of 			Just k -> go k (mkActionItem (k, AssociatedFile (Just f)))-			Nothing -> giveup $ "not an annexed file: " ++ f+			Nothing -> giveup $ "not an annexed file: " ++ fromRawFilePath f 	Right k -> go k (mkActionItem k)   where 	go k ai = starting "metadata" ai $ do
Command/Migrate.hs view
@@ -28,16 +28,16 @@ seek :: CmdParams -> CommandSeek seek = withFilesInGit (commandAction . (whenAnnexed start)) <=< workTreeItems -start :: FilePath -> Key -> CommandStart+start :: RawFilePath -> Key -> CommandStart start file key = do 	forced <- Annex.getState Annex.force-	v <- Backend.getBackend file key+	v <- Backend.getBackend (fromRawFilePath file) key 	case v of 		Nothing -> stop 		Just oldbackend -> do 			exists <- inAnnex key 			newbackend <- maybe defaultBackend return -				=<< chooseBackend file+				=<< chooseBackend (fromRawFilePath file) 			if (newbackend /= oldbackend || upgradableKey oldbackend key || forced) && exists 				then starting "migrate" (mkActionItem (key, file)) $ 					perform file key oldbackend newbackend@@ -63,7 +63,7 @@  - data cannot get corrupted after the fsck but before the new key is  - generated.  -}-perform :: FilePath -> Key -> Backend -> Backend -> CommandPerform+perform :: RawFilePath -> Key -> Backend -> Backend -> CommandPerform perform file oldkey oldbackend newbackend = go =<< genkey (fastMigrate oldbackend)   where 	go Nothing = stop@@ -85,8 +85,8 @@ 	genkey Nothing = do 		content <- calcRepo $ gitAnnexLocation oldkey 		let source = KeySource-			{ keyFilename = file-			, contentLocation = content+			{ keyFilename = fromRawFilePath file+			, contentLocation = fromRawFilePath  content 			, inodeCache = Nothing 			} 		v <- genKey source nullMeterUpdate (Just newbackend)
Command/Mirror.hs view
@@ -47,7 +47,7 @@ 		(withFilesInGit (commandAction . (whenAnnexed $ start o))) 		=<< workTreeItems (mirrorFiles o) -start :: MirrorOptions -> FilePath -> Key -> CommandStart+start :: MirrorOptions -> RawFilePath -> Key -> CommandStart start o file k = startKey o afile (k, ai)   where 	afile = AssociatedFile (Just file)@@ -75,4 +75,4 @@   where 	getnumcopies = case afile of 		AssociatedFile Nothing -> getNumCopies-		AssociatedFile (Just af) -> getFileNumCopies af+		AssociatedFile (Just af) -> getFileNumCopies (fromRawFilePath af)
Command/Move.hs view
@@ -57,13 +57,13 @@ seek o = startConcurrency transferStages $ do 	let go = whenAnnexed $ start (fromToOptions o) (removeWhen o) 	case batchOption o of-		Batch fmt -> batchFilesMatching fmt go+		Batch fmt -> batchFilesMatching fmt (go . toRawFilePath) 		NoBatch -> withKeyOptions (keyOptions o) False 			(commandAction . startKey (fromToOptions o) (removeWhen o)) 			(withFilesInGit (commandAction . go)) 			=<< workTreeItems (moveFiles o) -start :: FromToHereOptions -> RemoveWhen -> FilePath -> Key -> CommandStart+start :: FromToHereOptions -> RemoveWhen -> RawFilePath -> Key -> CommandStart start fromto removewhen f k = start' fromto removewhen afile k ai   where 	afile = AssociatedFile (Just f)
Command/Multicast.hs view
@@ -137,7 +137,8 @@ 				mk <- lookupFile f 				case mk of 					Nothing -> noop-					Just k -> withObjectLoc k (addlist f)+					Just k -> withObjectLoc k $+						addlist f . fromRawFilePath 			liftIO $ hClose h 			 			serverkey <- uftpKey
Command/P2P.hs view
@@ -5,6 +5,8 @@  - Licensed under the GNU AGPL version 3 or higher.  -} +{-# LANGUAGE OverloadedStrings #-}+ module Command.P2P where  import Command
Command/PostReceive.hs view
@@ -5,6 +5,8 @@  - Licensed under the GNU AGPL version 3 or higher.  -} +{-# LANGUAGE OverloadedStrings #-}+ module Command.PostReceive where  import Command
Command/PreCommit.hs view
@@ -53,11 +53,11 @@ 			(removeViewMetaData v)  addViewMetaData :: View -> ViewedFile -> Key -> CommandStart-addViewMetaData v f k = starting "metadata" (mkActionItem (k, f)) $+addViewMetaData v f k = starting "metadata" (mkActionItem (k, toRawFilePath f)) $ 	next $ changeMetaData k $ fromView v f  removeViewMetaData :: View -> ViewedFile -> Key -> CommandStart-removeViewMetaData v f k = starting "metadata" (mkActionItem (k, f)) $+removeViewMetaData v f k = starting "metadata" (mkActionItem (k, toRawFilePath f)) $ 	next $ changeMetaData k $ unsetMetaData $ fromView v f  changeMetaData :: Key -> MetaData -> CommandCleanup
Command/ReKey.hs view
@@ -19,6 +19,7 @@ import qualified Database.Keys import Annex.InodeSentinal import Utility.InodeCache+import qualified Utility.RawFilePath as R  cmd :: Command cmd = command "rekey" SectionPlumbing@@ -38,13 +39,13 @@  -- Split on the last space, since a FilePath can contain whitespace, -- but a Key very rarely does.-batchParser :: String -> Either String (FilePath, Key)+batchParser :: String -> Either String (RawFilePath, Key) batchParser s = case separate (== ' ') (reverse s) of 	(rk, rf) 		| null rk || null rf -> Left "Expected: \"file key\"" 		| otherwise -> case deserializeKey (reverse rk) of 			Nothing -> Left "bad key"-			Just k -> Right (reverse rf, k)+			Just k -> Right (toRawFilePath (reverse rf), k)  seek :: ReKeyOptions -> CommandSeek seek o = case batchOption o of@@ -52,9 +53,9 @@ 	NoBatch -> withPairs (commandAction . start . parsekey) (reKeyThese o)   where 	parsekey (file, skey) =-		(file, fromMaybe (giveup "bad key") (deserializeKey skey))+		(toRawFilePath file, fromMaybe (giveup "bad key") (deserializeKey skey)) -start :: (FilePath, Key) -> CommandStart+start :: (RawFilePath, Key) -> CommandStart start (file, newkey) = ifAnnexed file go stop   where 	go oldkey@@ -62,19 +63,19 @@ 		| otherwise = starting "rekey" (ActionItemWorkTreeFile file) $ 			perform file oldkey newkey -perform :: FilePath -> Key -> Key -> CommandPerform+perform :: RawFilePath -> Key -> Key -> CommandPerform perform file oldkey newkey = do 	ifM (inAnnex oldkey)  		( unlessM (linkKey file oldkey newkey) $ 			giveup "failed creating link from old to new key" 		, unlessM (Annex.getState Annex.force) $-			giveup $ file ++ " is not available (use --force to override)"+			giveup $ fromRawFilePath file ++ " is not available (use --force to override)" 		) 	next $ cleanup file oldkey newkey  {- Make a hard link to the old key content (when supported),  - to avoid wasting disk space. -}-linkKey :: FilePath -> Key -> Key -> Annex Bool+linkKey :: RawFilePath -> Key -> Key -> Annex Bool linkKey file oldkey newkey = ifM (isJust <$> isAnnexLink file)  	{- If the object file is already hardlinked to elsewhere, a hard 	 - link won't be made by getViaTmpFromDisk, but a copy instead.@@ -82,17 +83,17 @@ 	 - unlocked file, which would leave the new key unlocked 	 - and vulnerable to corruption. -} 	( getViaTmpFromDisk RetrievalAllKeysSecure DefaultVerify newkey $ \tmp -> unVerified $ do-		oldobj <- calcRepo (gitAnnexLocation oldkey)+		oldobj <- fromRawFilePath <$> calcRepo (gitAnnexLocation oldkey) 		isJust <$> linkOrCopy' (return True) newkey oldobj tmp Nothing 	, do 	 	{- The file being rekeyed is itself an unlocked file; if 		 - it's hard linked to the old key, that link must be broken. -}-		oldobj <- calcRepo (gitAnnexLocation oldkey)+		oldobj <- fromRawFilePath <$> calcRepo (gitAnnexLocation oldkey) 		v <- tryNonAsync $ do-			st <- liftIO $ getFileStatus file+			st <- liftIO $ R.getFileStatus file 			when (linkCount st > 1) $ do 				freezeContent oldobj-				replaceFile file $ \tmp -> do+				replaceFile (fromRawFilePath file) $ \tmp -> do 					unlessM (checkedCopyFile oldkey oldobj tmp Nothing) $ 						error "can't lock old key" 					thawContent tmp@@ -102,22 +103,22 @@ 				warning (show e) 				return False 			Right () -> do-				r <- linkToAnnex newkey file ic+				r <- linkToAnnex newkey (fromRawFilePath file) ic 				return $ case r of 					LinkAnnexFailed -> False 					LinkAnnexOk -> True 					LinkAnnexNoop -> True 	) -cleanup :: FilePath -> Key -> Key -> CommandCleanup+cleanup :: RawFilePath -> Key -> Key -> CommandCleanup cleanup file oldkey newkey = do 	ifM (isJust <$> isAnnexLink file) 		( do 			-- Update symlink to use the new key.-			liftIO $ removeFile file-			addLink file newkey Nothing+			liftIO $ removeFile (fromRawFilePath file)+			addLink (fromRawFilePath file) newkey Nothing 		, do-			mode <- liftIO $ catchMaybeIO $ fileMode <$> getFileStatus file+			mode <- liftIO $ catchMaybeIO $ fileMode <$> R.getFileStatus file 			liftIO $ whenM (isJust <$> isPointerFile file) $ 				writePointerFile file newkey mode 			stagePointerFile file mode =<< hashPointerFile newkey
Command/Reinject.hs view
@@ -42,7 +42,7 @@ startSrcDest :: [FilePath] -> CommandStart startSrcDest (src:dest:[]) 	| src == dest = stop-	| otherwise = notAnnexed src $ ifAnnexed dest go stop+	| otherwise = notAnnexed src $ ifAnnexed (toRawFilePath dest) go stop   where 	go key = starting "reinject" (ActionItemOther (Just src)) $ 		ifM (verifyKeyContent RetrievalAllKeysSecure DefaultVerify UnVerified key src)@@ -65,7 +65,7 @@ 				)  notAnnexed :: FilePath -> CommandStart -> CommandStart-notAnnexed src = ifAnnexed src $+notAnnexed src = ifAnnexed (toRawFilePath src) $ 	giveup $ "cannot used annexed file as src: " ++ src  perform :: FilePath -> Key -> CommandPerform
Command/ResolveMerge.hs view
@@ -24,7 +24,7 @@ start :: CommandStart start = starting "resolvemerge" (ActionItemOther Nothing) $ do 	us <- fromMaybe nobranch <$> inRepo Git.Branch.current-	d <- fromRepo Git.localGitDir+	d <- fromRawFilePath <$> fromRepo Git.localGitDir 	let merge_head = d </> "MERGE_HEAD" 	them <- fromMaybe (error nomergehead) . extractSha 		<$> liftIO (readFile merge_head)
Command/RmUrl.hs view
@@ -42,9 +42,11 @@ 		| otherwise -> Right (reverse rf, reverse ru)  start :: (FilePath, URLString) -> CommandStart-start (file, url) = flip whenAnnexed file $ \_ key ->-	starting "rmurl" (mkActionItem (key, AssociatedFile (Just file))) $+start (file, url) = flip whenAnnexed file' $ \_ key ->+	starting "rmurl" (mkActionItem (key, AssociatedFile (Just file'))) $ 		next $ cleanup url key+  where+	file' = toRawFilePath file  cleanup :: String -> Key -> CommandCleanup cleanup url key = do
Command/SendKey.hs view
@@ -46,7 +46,8 @@ fieldTransfer :: Direction -> Key -> (MeterUpdate -> Annex Bool) -> CommandStart fieldTransfer direction key a = do 	liftIO $ debugM "fieldTransfer" "transfer start"-	afile <- AssociatedFile <$> Fields.getField Fields.associatedFile+	afile <- AssociatedFile . (fmap toRawFilePath)+		<$> Fields.getField Fields.associatedFile 	ok <- maybe (a $ const noop) 		-- Using noRetry here because we're the sender. 		(\u -> runner (Transfer direction (toUUID u) (fromKey id key)) afile noRetry a)
Command/Smudge.hs view
@@ -18,7 +18,10 @@ import qualified Database.Keys import qualified Git.BuildVersion import Git.FilePath+import Git.Types+import Git.HashObject import qualified Git+import qualified Git.Ref import qualified Annex import Backend import Utility.Metered@@ -70,7 +73,7 @@ 	case parseLinkTargetOrPointerLazy b of 		Nothing -> noop 		Just k -> do-			topfile <- inRepo (toTopFilePath file)+			topfile <- inRepo (toTopFilePath (toRawFilePath file)) 			Database.Keys.addAssociatedFile k topfile 			void $ smudgeLog k topfile 	liftIO $ L.putStr b@@ -86,13 +89,16 @@ 		( liftIO $ L.hPut stdout b 		, case parseLinkTargetOrPointerLazy b of 			Just k -> do-				getMoveRaceRecovery k file+				getMoveRaceRecovery k (toRawFilePath file) 				liftIO $ L.hPut stdout b-			Nothing -> go b =<< catKeyFile file+			Nothing -> do+				let fileref = Git.Ref.fileRef (toRawFilePath file)+				indexmeta <- catObjectMetaData fileref+				go b indexmeta =<< catKey' fileref indexmeta 		) 	stop   where-	go b oldkey = ifM (shouldAnnex file oldkey)+	go b indexmeta oldkey = ifM (shouldAnnex file indexmeta oldkey) 		( do 			-- Before git 2.5, failing to consume all stdin here 			-- would cause a SIGPIPE and crash it.@@ -108,7 +114,7 @@ 			-- annexed and is unmodified. 			case oldkey of 				Nothing -> doingest oldkey-				Just ko -> ifM (isUnmodifiedCheap ko file)+				Just ko -> ifM (isUnmodifiedCheap ko (toRawFilePath file)) 					( liftIO $ emitPointer ko 					, doingest oldkey 					)@@ -141,7 +147,8 @@ 	-- git diff can run the clean filter on files outside the 	-- repository; can't annex those 	fileoutsiderepo = do-	        repopath <- liftIO . absPath =<< fromRepo Git.repoPath+	        repopath <- liftIO . absPath . fromRawFilePath+			=<< fromRepo Git.repoPath 		filepath <- liftIO $ absPath file 		return $ not $ dirContains repopath filepath @@ -152,17 +159,17 @@ -- added to the annex, so will be added to git. But some heuristics -- are used to avoid bad behavior: ----- If the index already contains the file, preserve its annexed/not annexed--- state. This prevents accidental conversions.+-- If the file is annexed in the index, keep it annexed.+-- This prevents accidental conversions. -- -- Otherwise, when the file's inode is the same as one that was used for -- annexed content before, annex it. This handles cases such as renaming an -- unlocked annexed file followed by git add, which the user naturally -- expects to behave the same as git mv.-shouldAnnex :: FilePath -> Maybe Key -> Annex Bool-shouldAnnex file moldkey = ifM (annexGitAddToAnnex <$> Annex.getGitConfig)-	( checkmatcher checkheuristics-	, checkheuristics+shouldAnnex :: FilePath -> Maybe (Sha, FileSize, ObjectType) -> Maybe Key -> Annex Bool+shouldAnnex file indexmeta moldkey = ifM (annexGitAddToAnnex <$> Annex.getGitConfig)+	( checkunchangedgitfile $ checkmatcher checkheuristics+	, checkunchangedgitfile checkheuristics 	)   where 	checkmatcher d = do@@ -173,10 +180,35 @@ 		Just _ -> return True 		Nothing -> checkknowninode -	checkknowninode = withTSDelta (liftIO . genInodeCache file) >>= \case+	checkknowninode = withTSDelta (liftIO . genInodeCache (toRawFilePath file)) >>= \case 		Nothing -> pure False 		Just ic -> Database.Keys.isInodeKnown ic =<< sentinalStatus +	-- This checks for a case where the file had been added to git+	-- previously, not to the annex before, and its content is not+	-- changed, but git is running the clean filter again on it+	-- (eg because its mtime or inode changed, or just because git feels+	-- like it). Such a file should not be added to the annex, even if+	-- annex.largefiles now matches it, because the content is not+	-- changed.+	checkunchangedgitfile cont = case (moldkey, indexmeta) of+		(Nothing, Just (sha, sz, _)) -> liftIO (catchMaybeIO (getFileSize file)) >>= \case+			Just sz' | sz' == sz -> do+				-- The size is the same, so the file+				-- is not much larger than what was stored+				-- in git before, so it won't be out of+				-- line to hash it. However, the content+				-- is prevented from being stored in git+				-- when hashing.+				h <- inRepo $ hashObjectStart False+				sha' <- liftIO $ hashFile h file+				liftIO $ hashObjectStop h+				if sha' == sha+					then return False+					else cont+			_ -> cont+		_ -> cont+ emitPointer :: Key -> IO () emitPointer = S.putStr . formatPointer @@ -187,7 +219,7 @@ -- This also handles the case where a copy of a pointer file is made, -- then git-annex gets the content, and later git add is run on -- the pointer copy. It will then be populated with the content.-getMoveRaceRecovery :: Key -> FilePath -> Annex ()+getMoveRaceRecovery :: Key -> RawFilePath -> Annex () getMoveRaceRecovery k file = void $ tryNonAsync $ 	whenM (inAnnex k) $ do 		obj <- calcRepo (gitAnnexLocation k)@@ -204,11 +236,11 @@  updateSmudged :: Restage -> Annex () updateSmudged restage = streamSmudged $ \k topf -> do-	f <- fromRepo $ fromTopFilePath topf+	f <- fromRepo (fromTopFilePath topf) 	whenM (inAnnex k) $ do 		obj <- calcRepo (gitAnnexLocation k) 		unlessM (isJust <$> populatePointerFile restage k obj f) $ 			liftIO (isPointerFile f) >>= \case 				Just k' | k' == k -> toplevelWarning False $-					"unable to populate worktree file " ++ f+					"unable to populate worktree file " ++ fromRawFilePath f 				_ -> noop
Command/Status.hs view
@@ -61,6 +61,6 @@ displayStatus s = do 	let c = statusChar s 	absf <- fromRepo $ fromTopFilePath (statusFile s)-	f <- liftIO $ relPathCwdToFile absf+	f <- liftIO $ relPathCwdToFile $ fromRawFilePath absf 	unlessM (showFullJSON $ JSONChunk [("status", [c]), ("file", f)]) $ 		liftIO $ putStrLn $ [c] ++ " " ++ f
Command/Sync.hs view
@@ -7,6 +7,7 @@  -}  {-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE OverloadedStrings #-}  module Command.Sync ( 	cmd,@@ -225,7 +226,7 @@  - of the repo. This also means that sync always acts on all files in the  - repository, not just on a subdirectory. -} prepMerge :: Annex ()-prepMerge = Annex.changeDirectory =<< fromRepo Git.repoPath+prepMerge = Annex.changeDirectory . fromRawFilePath =<< fromRepo Git.repoPath  mergeConfig :: [Git.Merge.MergeConfig]	 mergeConfig = @@ -408,7 +409,7 @@ 			let branch = Git.Ref b 			let subdir = if null s 				then Nothing-				else Just (asTopFilePath s)+				else Just (asTopFilePath (toRawFilePath s)) 			Command.Import.seekRemote remote branch subdir 			void $ mergeRemote remote currbranch mergeconfig 				(resolveMergeOverride o)@@ -467,7 +468,7 @@ 			( liftIO $ do 				p <- readProgramFile 				boolSystem' p [Param "post-receive"]-					(\cp -> cp { cwd = Just wt })+					(\cp -> cp { cwd = Just (fromRawFilePath wt) }) 			, return True 			) 	  where
Command/TestRemote.hs view
@@ -168,7 +168,7 @@ 		get 	, Just $ check "fsck downloaded object" fsck 	, Just $ check "retrieveKeyFile resume from 33%" $ do-		loc <- Annex.calcRepo (gitAnnexLocation k)+		loc <- fromRawFilePath <$> Annex.calcRepo (gitAnnexLocation k) 		tmp <- prepTmp k 		partial <- liftIO $ bracket (openBinaryFile loc ReadMode) hClose $ \h -> do 			sz <- hFileSize h@@ -184,7 +184,7 @@ 		get 	, Just $ check "fsck downloaded object" fsck 	, Just $ check "retrieveKeyFile resume from end" $ do-		loc <- Annex.calcRepo (gitAnnexLocation k)+		loc <- fromRawFilePath <$> Annex.calcRepo (gitAnnexLocation k) 		tmp <- prepTmp k 		void $ liftIO $ copyFileExternal CopyAllMetaData loc tmp 		lockContentForRemoval k removeAnnex@@ -236,11 +236,11 @@ 	]   where 	testexportdirectory = "testremote-export"-	testexportlocation = mkExportLocation (testexportdirectory </> "location")+	testexportlocation = mkExportLocation (toRawFilePath (testexportdirectory </> "location")) 	check desc a = testCase desc $ 		Annex.eval st (Annex.setOutput QuietOutput >> a) @? "failed" 	storeexport k = do-		loc <- Annex.calcRepo (gitAnnexLocation k)+		loc <- fromRawFilePath <$> Annex.calcRepo (gitAnnexLocation k) 		Remote.storeExport ea loc k testexportlocation nullMeterUpdate 	retrieveexport k = withTmpFile "exported" $ \tmp h -> do 		liftIO $ hClose h@@ -252,7 +252,7 @@ 	removeexport k = Remote.removeExport ea k testexportlocation 	removeexportdirectory = case Remote.removeExportDirectory ea of 		Nothing -> return True-		Just a -> a (mkExportDirectory testexportdirectory)+		Just a -> a (mkExportDirectory (toRawFilePath testexportdirectory))  testUnavailable :: Annex.AnnexState -> Remote -> Key -> [TestTree] testUnavailable st r k =@@ -326,7 +326,7 @@ 	return k  getReadonlyKey :: Remote -> FilePath -> Annex Key-getReadonlyKey r f = lookupFile f >>= \case+getReadonlyKey r f = lookupFile (toRawFilePath f) >>= \case 	Nothing -> giveup $ f ++ " is not an annexed file" 	Just k -> do 		unlessM (inAnnex k) $
Command/TransferInfo.hs view
@@ -41,7 +41,8 @@ 	case deserializeKey k of 		Nothing -> error "bad key" 		(Just key) -> whenM (inAnnex key) $ do-			afile <- AssociatedFile <$> Fields.getField Fields.associatedFile+			afile <- AssociatedFile . (fmap toRawFilePath)+				<$> Fields.getField Fields.associatedFile 			u <- maybe (error "missing remoteuuid") toUUID 				<$> Fields.getField Fields.remoteUUID 			let t = Transfer
Command/TransferKeys.hs view
@@ -116,10 +116,10 @@ 	deserialize _ = Nothing  instance TCSerialized AssociatedFile where-	serialize (AssociatedFile (Just f)) = f+	serialize (AssociatedFile (Just f)) = fromRawFilePath f 	serialize (AssociatedFile Nothing) = "" 	deserialize "" = Just (AssociatedFile Nothing)-	deserialize f = Just (AssociatedFile (Just f))+	deserialize f = Just (AssociatedFile (Just (toRawFilePath f)))  instance TCSerialized RemoteName where 	serialize n = n
Command/Unannex.hs view
@@ -25,28 +25,28 @@ seek :: CmdParams -> CommandSeek seek ps = (withFilesInGit $ commandAction . whenAnnexed start) =<< workTreeItems ps -start :: FilePath -> Key -> CommandStart+start :: RawFilePath -> Key -> CommandStart start file key = stopUnless (inAnnex key) $ 	starting "unannex" (mkActionItem (key, file)) $ 		perform file key -perform :: FilePath -> Key -> CommandPerform+perform :: RawFilePath -> Key -> CommandPerform perform file key = do-	liftIO $ removeFile file+	liftIO $ removeFile (fromRawFilePath file) 	inRepo $ Git.Command.run 		[ Param "rm" 		, Param "--cached" 		, Param "--force" 		, Param "--quiet" 		, Param "--"-		, File file+		, File (fromRawFilePath file) 		] 	next $ cleanup file key -cleanup :: FilePath -> Key -> CommandCleanup+cleanup :: RawFilePath -> Key -> CommandCleanup cleanup file key = do 	Database.Keys.removeAssociatedFile key =<< inRepo (toTopFilePath file)-	src <- calcRepo $ gitAnnexLocation key+	src <- fromRawFilePath <$> calcRepo (gitAnnexLocation key) 	ifM (Annex.getState Annex.fast) 		( do 			-- Only make a hard link if the annexed file does not@@ -61,11 +61,12 @@ 		, copyfrom src 		)   where+	file' = fromRawFilePath file 	copyfrom src = -		thawContent file `after` liftIO (copyFileExternal CopyAllMetaData src file)+		thawContent file' `after` liftIO (copyFileExternal CopyAllMetaData src file') 	hardlinkfrom src = 		-- creating a hard link could fall; fall back to copying-		ifM (liftIO $ catchBoolIO $ createLink src file >> return True)+		ifM (liftIO $ catchBoolIO $ createLink src file' >> return True) 			( return True 			, copyfrom src 			)
Command/Undo.hs view
@@ -27,9 +27,9 @@ seek ps = do 	-- Safety first; avoid any undo that would touch files that are not 	-- in the index.-	(fs, cleanup) <- inRepo $ LsFiles.notInRepo False ps+	(fs, cleanup) <- inRepo $ LsFiles.notInRepo False (map toRawFilePath ps) 	unless (null fs) $-		giveup $ "Cannot undo changes to files that are not checked into git: " ++ unwords fs+		giveup $ "Cannot undo changes to files that are not checked into git: " ++ unwords (map fromRawFilePath fs) 	void $ liftIO $ cleanup  	-- Committing staged changes before undo allows later@@ -51,7 +51,7 @@ 	-- Get the reversed diff that needs to be applied to undo. 	(diff, cleanup) <- inRepo $ 		diffLog [Param "-R", Param "--", Param p]-	top <- inRepo $ toTopFilePath p+	top <- inRepo $ toTopFilePath $ toRawFilePath p 	let diff' = filter (`isDiffOf` top) diff 	liftIO $ streamUpdateIndex g (map stageDiffTreeItem diff') @@ -59,7 +59,8 @@ 	-- and then any adds. This order is necessary to handle eg, removing 	-- a directory and replacing it with a file. 	let (removals, adds) = partition (\di -> dstsha di == nullSha) diff'-	let mkrel di = liftIO $ relPathCwdToFile $ fromTopFilePath (file di) g+	let mkrel di = liftIO $ relPathCwdToFile $ fromRawFilePath $+		fromTopFilePath (file di) g  	forM_ removals $ \di -> do 		f <- mkrel di
Command/Uninit.hs view
@@ -17,6 +17,7 @@ import Annex.Content import Annex.Init import Utility.FileMode+import qualified Utility.RawFilePath as R  cmd :: Command cmd = addCheck check $ @@ -29,19 +30,19 @@ 	b <- current_branch 	when (b == Annex.Branch.name) $ giveup $ 		"cannot uninit when the " ++ Git.fromRef b ++ " branch is checked out"-	top <- fromRepo Git.repoPath+	top <- fromRawFilePath <$> fromRepo Git.repoPath 	currdir <- liftIO getCurrentDirectory 	whenM ((/=) <$> liftIO (absPath top) <*> liftIO (absPath currdir)) $ 		giveup "can only run uninit from the top of the git repository"   where-	current_branch = Git.Ref . Prelude.head . lines <$> revhead+	current_branch = Git.Ref . Prelude.head . lines . decodeBS' <$> revhead 	revhead = inRepo $ Git.Command.pipeReadStrict 		[Param "rev-parse", Param "--abbrev-ref", Param "HEAD"]  seek :: CmdParams -> CommandSeek seek ps = do 	l <- workTreeItems ps-	withFilesNotInGit False (commandAction . whenAnnexed startCheckIncomplete) l+	withFilesNotInGit False (commandAction . whenAnnexed (startCheckIncomplete . fromRawFilePath)) l 	Annex.changeState $ \s -> s { Annex.fast = True } 	withFilesInGit (commandAction . whenAnnexed Command.Unannex.start) l 	finish@@ -57,7 +58,7 @@  finish :: Annex () finish = do-	annexdir <- fromRepo gitAnnexDir+	annexdir <- fromRawFilePath <$> fromRepo gitAnnexDir 	annexobjectdir <- fromRepo gitAnnexObjectDir 	leftovers <- removeUnannexed =<< listKeys InAnnex 	prepareRemoveAnnexDir annexdir@@ -117,5 +118,5 @@ 		, go (k:c) ks 		) 	enoughlinks f = catchBoolIO $ do-		s <- getFileStatus f+		s <- R.getFileStatus f 		return $ linkCount s > 1
Command/Unlock.hs view
@@ -14,6 +14,7 @@ import Annex.ReplaceFile import Git.FilePath import qualified Database.Keys+import qualified Utility.RawFilePath as R  cmd :: Command cmd = mkcmd "unlock" "unlock files for modification"@@ -31,17 +32,17 @@ {- 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 :: FilePath -> Key -> CommandStart+start :: RawFilePath -> Key -> CommandStart start file key = ifM (isJust <$> isAnnexLink file) 	( starting "unlock" (mkActionItem (key, AssociatedFile (Just file))) $ 		perform file key 	, stop 	) -perform :: FilePath -> Key -> CommandPerform+perform :: RawFilePath -> Key -> CommandPerform perform dest key = do-	destmode <- liftIO $ catchMaybeIO $ fileMode <$> getFileStatus dest-	replaceFile dest $ \tmp ->+	destmode <- liftIO $ catchMaybeIO $ fileMode <$> R.getFileStatus dest+	replaceFile (fromRawFilePath dest) $ \tmp -> 		ifM (inAnnex key) 			( do 				r <- linkFromAnnex key tmp destmode@@ -49,11 +50,11 @@ 					LinkAnnexOk -> return () 					LinkAnnexNoop -> return () 					LinkAnnexFailed -> error "unlock failed"-			, liftIO $ writePointerFile tmp key destmode+			, liftIO $ writePointerFile (toRawFilePath tmp) key destmode 			) 	next $ cleanup dest key destmode -cleanup ::  FilePath -> Key -> Maybe FileMode -> CommandCleanup+cleanup ::  RawFilePath -> Key -> Maybe FileMode -> CommandCleanup cleanup dest key destmode = do 	stagePointerFile dest destmode =<< hashPointerFile key 	Database.Keys.addAssociatedFile key =<< inRepo (toTopFilePath dest)
Command/Unused.hs view
@@ -192,10 +192,10 @@ 	calla k _ _ = a k  {- Folds an action over keys and files referenced in a particular directory. -}-withKeysFilesReferencedIn :: FilePath -> v -> (Key -> FilePath -> v -> Annex v) -> Annex v+withKeysFilesReferencedIn :: FilePath -> v -> (Key -> RawFilePath -> v -> Annex v) -> Annex v withKeysFilesReferencedIn = withKeysReferenced' . Just -withKeysReferenced' :: Maybe FilePath -> v -> (Key -> FilePath -> v -> Annex v) -> Annex v+withKeysReferenced' :: Maybe FilePath -> v -> (Key -> RawFilePath -> v -> Annex v) -> Annex v withKeysReferenced' mdir initial a = do 	(files, clean) <- getfiles 	r <- go initial files@@ -209,7 +209,7 @@ 				top <- fromRepo Git.repoPath 				inRepo $ LsFiles.allFiles [top] 			)-		Just dir -> inRepo $ LsFiles.inRepo [dir]+		Just dir -> inRepo $ LsFiles.inRepo [toRawFilePath dir] 	go v [] = return v 	go v (f:fs) = do 		mk <- lookupFile f@@ -221,7 +221,8 @@  withKeysReferencedDiffGitRefs :: RefSpec -> (Key -> Annex ()) -> Annex () withKeysReferencedDiffGitRefs refspec a = do-	rs <- relevantrefs <$> inRepo (Git.Command.pipeReadStrict [Param "show-ref"])+	rs <- relevantrefs . decodeBS'+		<$> inRepo (Git.Command.pipeReadStrict [Param "show-ref"]) 	shaHead <- maybe (return Nothing) (inRepo . Git.Ref.sha) 		=<< inRepo Git.Branch.currentUnsafe 	let haveHead = any (\(shaRef, _) -> Just shaRef == shaHead) rs
Command/Vicfg.hs view
@@ -31,6 +31,7 @@ import Types.ScheduledActivity import Types.NumCopies import Remote+import Git.Types (ConfigKey(..), fromConfigKey, fromConfigValue)  cmd :: Command cmd = command "vicfg" SectionSetup "edit configuration in git-annex branch"@@ -70,7 +71,7 @@ 	, cfgRequiredContentMap :: M.Map UUID PreferredContentExpression 	, cfgGroupPreferredContentMap :: M.Map Group PreferredContentExpression 	, cfgScheduleMap :: M.Map UUID [ScheduledActivity]-	, cfgGlobalConfigs :: M.Map ConfigName ConfigValue+	, cfgGlobalConfigs :: M.Map ConfigKey ConfigValue 	, cfgNumCopies :: Maybe NumCopies 	} @@ -218,9 +219,9 @@ 		[ com "Other global configuration" 		] 		(\(s, g) -> gline g s)-		(\g -> gline g "")+		(\g -> gline g mempty) 	  where-		gline g val = [ unwords ["config", g, "=", val] ]+		gline k v = [ unwords ["config", fromConfigKey k, "=", fromConfigValue v] ]  	line setting u val = 		[ com $ "(for " ++ fromUUIDDesc (fromMaybe mempty (M.lookup u descs)) ++ ")"@@ -308,7 +309,7 @@ 				let m = M.insert u l (cfgScheduleMap cfg) 				in Right $ cfg { cfgScheduleMap = m } 		| setting == "config" =-			let m = M.insert f val (cfgGlobalConfigs cfg)+			let m = M.insert (ConfigKey (encodeBS' f)) (ConfigValue (encodeBS' val)) (cfgGlobalConfigs cfg) 			in Right $ cfg { cfgGlobalConfigs = m } 		| setting == "numcopies" = case readish val of 			Nothing -> Left "parse error (expected an integer)"
Command/View.hs view
@@ -99,9 +99,10 @@ 		 - and this pollutes the view, so remove them. 		 - (However, emptry directories used by submodules are not 		 - removed.) -}-		top <- liftIO . absPath =<< fromRepo Git.repoPath+		top <- liftIO . absPath . fromRawFilePath =<< fromRepo Git.repoPath 		(l, cleanup) <- inRepo $-			LsFiles.notInRepoIncludingEmptyDirectories False [top]+			LsFiles.notInRepoIncludingEmptyDirectories False+				[toRawFilePath top] 		forM_ l (removeemptydir top) 		liftIO $ void cleanup 		unlessM (liftIO $ doesDirectoryExist here) $ do@@ -110,7 +111,7 @@   where 	removeemptydir top d = do 		p <- inRepo $ toTopFilePath d-		liftIO $ tryIO $ removeDirectory (top </> getTopFilePath p)+		liftIO $ tryIO $ removeDirectory (top </> fromRawFilePath (getTopFilePath p)) 	cwdmissing top = unlines 		[ "This view does not include the subdirectory you are currently in." 		, "Perhaps you should:  cd " ++ top
Command/WebApp.hs view
@@ -6,6 +6,7 @@  -}  {-# LANGUAGE CPP #-}+{-# LANGUAGE OverloadedStrings #-}  module Command.WebApp where @@ -22,6 +23,7 @@ import Utility.UserInfo import Annex.Init import qualified Git+import Git.Types (fromConfigValue) import qualified Git.Config import qualified Git.CurrentRepo import qualified Annex@@ -229,7 +231,7 @@  {- web.browser is a generic git config setting for a web browser program -} webBrowser :: Git.Repo -> Maybe FilePath-webBrowser = Git.Config.getMaybe "web.browser"+webBrowser = fmap fromConfigValue <$> Git.Config.getMaybe "web.browser"  fileUrl :: FilePath -> String fileUrl file = "file://" ++ file
Command/Whereis.hs view
@@ -40,14 +40,14 @@ 	m <- remoteMap id 	let go = whenAnnexed $ start m 	case batchOption o of-		Batch fmt -> batchFilesMatching fmt go+		Batch fmt -> batchFilesMatching fmt (go . toRawFilePath) 		NoBatch ->  			withKeyOptions (keyOptions o) False 				(commandAction . startKeys m) 				(withFilesInGit (commandAction . go)) 				=<< workTreeItems (whereisFiles o) -start :: M.Map UUID Remote -> FilePath -> Key -> CommandStart+start :: M.Map UUID Remote -> RawFilePath -> Key -> CommandStart start remotemap file key = startKeys remotemap (key, mkActionItem (key, afile))   where 	afile = AssociatedFile (Just file)
Config.hs view
@@ -6,6 +6,7 @@  -}  {-# LANGUAGE TypeSynonymInstances, FlexibleInstances #-}+{-# LANGUAGE OverloadedStrings #-}  module Config where @@ -22,25 +23,26 @@ import qualified Annex.SpecialRemote.Config as SpecialRemote  import qualified Data.Map as M--type UnqualifiedConfigKey = String-data ConfigKey = ConfigKey String+import qualified Data.ByteString as S -instance Show ConfigKey where-	show (ConfigKey s) = s+type UnqualifiedConfigKey = S.ByteString  {- Looks up a setting in git config. This is not as efficient as using the  - GitConfig type. -}-getConfig :: ConfigKey -> String -> Annex String-getConfig (ConfigKey key) d = fromRepo $ Git.Config.get key d+getConfig :: ConfigKey -> ConfigValue -> Annex ConfigValue+getConfig key d = fromRepo $ Git.Config.get key d -getConfigMaybe :: ConfigKey -> Annex (Maybe String)-getConfigMaybe (ConfigKey key) = fromRepo $ Git.Config.getMaybe key+getConfigMaybe :: ConfigKey -> Annex (Maybe ConfigValue)+getConfigMaybe key = fromRepo $ Git.Config.getMaybe key  {- Changes a git config setting in both internal state and .git/config -} setConfig :: ConfigKey -> String -> Annex () setConfig (ConfigKey key) value = do-	inRepo $ Git.Command.run [Param "config", Param key, Param value]+	inRepo $ Git.Command.run+		[ Param "config"+		, Param (decodeBS' key)+		, Param value+		] 	reloadConfig  reloadConfig :: Annex ()@@ -48,7 +50,7 @@  {- Unsets a git config setting. (Leaves it in state.) -} unsetConfig :: ConfigKey -> Annex ()-unsetConfig (ConfigKey key) = void $ inRepo $ Git.Config.unset key+unsetConfig key = void $ inRepo $ Git.Config.unset key  class RemoteNameable r where 	getRemoteName :: r -> RemoteName@@ -68,11 +70,11 @@ {- A per-remote config setting in git config. -} remoteConfig :: RemoteNameable r => r -> UnqualifiedConfigKey -> ConfigKey remoteConfig r key = ConfigKey $-	"remote." ++ getRemoteName r ++ ".annex-" ++ key+	"remote." <> encodeBS' (getRemoteName r) <> ".annex-" <> key  {- A global annex setting in git config. -} annexConfig :: UnqualifiedConfigKey -> ConfigKey-annexConfig key = ConfigKey $ "annex." ++ key+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
Config/GitConfig.hs view
@@ -1,6 +1,6 @@ {- git-annex configuration  -- - Copyright 2017 Joey Hess <id@joeyh.name>+ - Copyright 2017-2019 Joey Hess <id@joeyh.name>  -  - Licensed under the GNU AGPL version 3 or higher.  -}@@ -15,22 +15,26 @@  {- Gets a specific setting from GitConfig. If necessary, loads the  - repository-global defaults when the GitConfig does not yet - - have a value. -}+ - have a value.+ -+ - Note: Be sure to add the config value to mergeGitConfig.+ -} getGitConfigVal :: (GitConfig -> Configurable a) -> Annex a-getGitConfigVal f = do-	v <- f <$> Annex.getGitConfig-	case v of-		HasConfig c -> return c-		DefaultConfig _ -> do-			r <- Annex.gitRepo-			m <- loadGlobalConfig-			let globalgc = extractGitConfig (r { config = m })-			-- This merge of the repo-global config and the git-			-- config makes all repository-global default-			-- values populate the GitConfig with HasConfig-			-- values, so it will only need to be done once.-			Annex.changeGitConfig (\gc -> mergeGitConfig gc globalgc)-			v' <- f <$> Annex.getGitConfig-			case v' of-				HasConfig c -> return c-				DefaultConfig d -> return d+getGitConfigVal f = getGitConfigVal' f >>= \case+	HasGlobalConfig c -> return c+	DefaultConfig d -> return d+	HasGitConfig c -> return c++getGitConfigVal' :: (GitConfig -> Configurable a) -> Annex (Configurable a)+getGitConfigVal' f = (f <$> Annex.getGitConfig) >>= \case+	DefaultConfig _ -> do+		r <- Annex.gitRepo+		m <- loadGlobalConfig+		let globalgc = extractGitConfig FromGlobalConfig (r { config = m })+		-- This merge of the repo-global config and the git+		-- 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)+		f <$> Annex.getGitConfig+	c -> return c
Config/Smudge.hs view
@@ -5,12 +5,15 @@  - Licensed under the GNU AGPL version 3 or higher.  -} +{-# LANGUAGE OverloadedStrings #-}+ module Config.Smudge where  import Annex.Common import qualified Annex import qualified Git import qualified Git.Command+import Git.Types import Config  configureSmudgeFilter :: Annex ()
Database/Export.hs view
@@ -128,28 +128,28 @@ addExportedLocation h k el = queueDb h $ do 	void $ insertUnique $ Exported ik ef 	let edirs = map-		(\ed -> ExportedDirectory (toSFilePath (fromExportDirectory ed)) ef)+		(\ed -> ExportedDirectory (toSFilePath (fromRawFilePath (fromExportDirectory ed))) ef) 		(exportDirectories el) 	putMany edirs   where 	ik = toIKey k-	ef = toSFilePath (fromExportLocation el)+	ef = toSFilePath $ fromRawFilePath $ fromExportLocation el  removeExportedLocation :: ExportHandle -> Key -> ExportLocation -> IO () removeExportedLocation h k el = queueDb h $ do 	deleteWhere [ExportedKey ==. ik, ExportedFile ==. ef]-	let subdirs = map (toSFilePath . fromExportDirectory)+	let subdirs = map (toSFilePath . fromRawFilePath . fromExportDirectory) 		(exportDirectories el) 	deleteWhere [ExportedDirectoryFile ==. ef, ExportedDirectorySubdir <-. subdirs]   where 	ik = toIKey k-	ef = toSFilePath (fromExportLocation el)+	ef = toSFilePath $ fromRawFilePath $ fromExportLocation el  {- Note that this does not see recently queued changes. -} getExportedLocation :: ExportHandle -> Key -> IO [ExportLocation] getExportedLocation (ExportHandle h _) k = H.queryDbQueue h $ do 	l <- selectList [ExportedKey ==. ik] []-	return $ map (mkExportLocation . fromSFilePath . exportedFile . entityVal) l+	return $ map (mkExportLocation . toRawFilePath . fromSFilePath . exportedFile . entityVal) l   where 	ik = toIKey k @@ -159,13 +159,13 @@ 	l <- selectList [ExportedDirectorySubdir ==. ed] [] 	return $ null l   where-	ed = toSFilePath $ fromExportDirectory d+	ed = toSFilePath $ fromRawFilePath $ fromExportDirectory d  {- Get locations in the export that might contain a key. -} getExportTree :: ExportHandle -> Key -> IO [ExportLocation] getExportTree (ExportHandle h _) k = H.queryDbQueue h $ do 	l <- selectList [ExportTreeKey ==. ik] []-	return $ map (mkExportLocation . fromSFilePath . exportTreeFile . entityVal) l+	return $ map (mkExportLocation . toRawFilePath . fromSFilePath . exportTreeFile . entityVal) l   where 	ik = toIKey k @@ -181,21 +181,21 @@ 	map (fromIKey . exportTreeKey . entityVal)  		<$> selectList [ExportTreeFile ==. ef] []   where-	ef = toSFilePath (fromExportLocation el)+	ef = toSFilePath (fromRawFilePath $ fromExportLocation el)  addExportTree :: ExportHandle -> Key -> ExportLocation -> IO () addExportTree h k loc = queueDb h $ 	void $ insertUnique $ ExportTree ik ef   where 	ik = toIKey k-	ef = toSFilePath (fromExportLocation loc)+	ef = toSFilePath (fromRawFilePath $ fromExportLocation loc)  removeExportTree :: ExportHandle -> Key -> ExportLocation -> IO () removeExportTree h k loc = queueDb h $ 	deleteWhere [ExportTreeKey ==. ik, ExportTreeFile ==. ef]   where 	ik = toIKey k-	ef = toSFilePath (fromExportLocation loc)+	ef = toSFilePath (fromRawFilePath $ fromExportLocation loc)  -- An action that is passed the old and new values that were exported, -- and updates state.
Database/Keys.hs view
@@ -43,6 +43,9 @@ import Git.Types import Git.Index +import qualified Data.ByteString as S+import qualified System.FilePath.ByteString as P+ {- Runs an action that reads from the database.  -  - If the database doesn't already exist, it's not created; mempty is@@ -169,13 +172,13 @@ removeAssociatedFile k = runWriterIO . SQL.removeAssociatedFile (toIKey k)  {- Stats the files, and stores their InodeCaches. -}-storeInodeCaches :: Key -> [FilePath] -> Annex ()+storeInodeCaches :: Key -> [RawFilePath] -> Annex () storeInodeCaches k fs = storeInodeCaches' k fs [] -storeInodeCaches' :: Key -> [FilePath] -> [InodeCache] -> Annex ()+storeInodeCaches' :: Key -> [RawFilePath] -> [InodeCache] -> Annex () storeInodeCaches' k fs ics = withTSDelta $ \d -> 	addInodeCaches k . (++ ics) . catMaybes-		=<< liftIO (mapM (`genInodeCache` d) fs)+		=<< liftIO (mapM (\f -> genInodeCache f d) fs)  addInodeCaches :: Key -> [InodeCache] -> Annex () addInodeCaches k is = runWriterIO $ SQL.addInodeCaches (toIKey k) is@@ -223,7 +226,7 @@ reconcileStaged qh = do 	gitindex <- inRepo currentIndexFile 	indexcache <- fromRepo gitAnnexKeysDbIndexCache-	withTSDelta (liftIO . genInodeCache gitindex) >>= \case+	withTSDelta (liftIO . genInodeCache (toRawFilePath gitindex)) >>= \case 		Just cur ->  			liftIO (maybe Nothing readInodeCache <$> catchMaybeIO (readFile indexcache)) >>= \case 				Nothing -> go cur indexcache@@ -235,7 +238,7 @@   where 	go cur indexcache = do 		(l, cleanup) <- inRepo $ pipeNullSplit diff-		changed <- procdiff l False+		changed <- procdiff (map decodeBL' l) False 		void $ liftIO cleanup 		-- Flush database changes immediately 		-- so other processes can see them.@@ -262,7 +265,8 @@ 		-- perfect. A file could start with this and not be a 		-- pointer file. And a pointer file that is replaced with 		-- a non-pointer file will match this.-		, Param $ "-G^" ++ toInternalGitPath (pathSeparator:objectDir)+		, Param $ "-G^" ++ fromRawFilePath (toInternalGitPath $+			P.pathSeparator `S.cons` objectDir') 		-- Don't include files that were deleted, because this only 		-- wants to update information for files that are present 		-- in the index.@@ -277,8 +281,8 @@ 	procdiff (info:file:rest) changed = case words info of 		((':':_srcmode):dstmode:_srcsha:dstsha:_change:[]) 			-- Only want files, not symlinks-			| dstmode /= fmtTreeItemType TreeSymlink -> do-				maybe noop (reconcile (asTopFilePath file)) +			| dstmode /= decodeBS' (fmtTreeItemType TreeSymlink) -> do+				maybe noop (reconcile (asTopFilePath (toRawFilePath file))) 					=<< catKey (Ref dstsha) 				procdiff rest True 			| otherwise -> procdiff rest changed
Database/Keys/SQL.hs view
@@ -17,6 +17,7 @@ import Database.Handle import qualified Database.Queue as H import Utility.InodeCache+import Utility.FileSystemEncoding import Git.FilePath  import Database.Persist.Sql@@ -69,7 +70,7 @@ 	deleteWhere [AssociatedFile ==. af, AssociatedKey !=. ik] 	void $ insertUnique $ Associated ik af   where-	af = toSFilePath (getTopFilePath f)+	af = toSFilePath (fromRawFilePath (getTopFilePath f))  -- Does not remove any old association for a file, but less expensive -- than addAssociatedFile. Calling dropAllAssociatedFiles first and then@@ -77,7 +78,7 @@ addAssociatedFileFast :: IKey -> TopFilePath -> WriteHandle -> IO () addAssociatedFileFast ik f = queueDb $ void $ insertUnique $ Associated ik af   where-	af = toSFilePath (getTopFilePath f)+	af = toSFilePath (fromRawFilePath (getTopFilePath f))  dropAllAssociatedFiles :: WriteHandle -> IO () dropAllAssociatedFiles = queueDb $@@ -88,7 +89,7 @@ getAssociatedFiles :: IKey -> ReadHandle -> IO [TopFilePath] getAssociatedFiles ik = readDb $ do 	l <- selectList [AssociatedKey ==. ik] []-	return $ map (asTopFilePath . fromSFilePath . associatedFile . entityVal) l+	return $ map (asTopFilePath . toRawFilePath . fromSFilePath . associatedFile . entityVal) l  {- Gets any keys that are on record as having a particular associated file.  - (Should be one or none but the database doesn't enforce that.) -}@@ -97,13 +98,13 @@ 	l <- selectList [AssociatedFile ==. af] [] 	return $ map (associatedKey . entityVal) l   where-	af = toSFilePath (getTopFilePath f)+	af = toSFilePath (fromRawFilePath (getTopFilePath f))  removeAssociatedFile :: IKey -> TopFilePath -> WriteHandle -> IO () removeAssociatedFile ik f = queueDb $ 	deleteWhere [AssociatedKey ==. ik, AssociatedFile ==. af]   where-	af = toSFilePath (getTopFilePath f)+	af = toSFilePath (fromRawFilePath (getTopFilePath f))  addInodeCaches :: IKey -> [InodeCache] -> WriteHandle -> IO () addInodeCaches ik is = queueDb $
Git.hs view
@@ -51,35 +51,35 @@ repoDescribe :: Repo -> String repoDescribe Repo { remoteName = Just name } = name repoDescribe Repo { location = Url url } = show url-repoDescribe Repo { location = Local { worktree = Just dir } } = dir-repoDescribe Repo { location = Local { gitdir = dir } } = dir-repoDescribe Repo { location = LocalUnknown dir } = dir+repoDescribe Repo { location = Local { worktree = Just dir } } = fromRawFilePath dir+repoDescribe Repo { location = Local { gitdir = dir } } = fromRawFilePath dir+repoDescribe Repo { location = LocalUnknown dir } = fromRawFilePath dir repoDescribe Repo { location = Unknown } = "UNKNOWN"  {- Location of the repo, either as a path or url. -} repoLocation :: Repo -> String repoLocation Repo { location = Url url } = show url-repoLocation Repo { location = Local { worktree = Just dir } } = dir-repoLocation Repo { location = Local { gitdir = dir } } = dir-repoLocation Repo { location = LocalUnknown dir } = dir+repoLocation Repo { location = Local { worktree = Just dir } } = fromRawFilePath dir+repoLocation Repo { location = Local { gitdir = dir } } = fromRawFilePath dir+repoLocation Repo { location = LocalUnknown dir } = fromRawFilePath dir repoLocation Repo { location = Unknown } = error "unknown repoLocation"  {- Path to a repository. For non-bare, this is the worktree, for bare,   - it's the gitdir, and for URL repositories, is the path on the remote  - host. -}-repoPath :: Repo -> FilePath-repoPath Repo { location = Url u } = unEscapeString $ uriPath u+repoPath :: Repo -> RawFilePath+repoPath Repo { location = Url u } = toRawFilePath $ unEscapeString $ uriPath u repoPath Repo { location = Local { worktree = Just d } } = d repoPath Repo { location = Local { gitdir = d } } = d repoPath Repo { location = LocalUnknown dir } = dir repoPath Repo { location = Unknown } = error "unknown repoPath" -repoWorkTree :: Repo -> Maybe FilePath+repoWorkTree :: Repo -> Maybe RawFilePath repoWorkTree Repo { location = Local { worktree = Just d } } = Just d repoWorkTree _ = Nothing  {- Path to a local repository's .git directory. -}-localGitDir :: Repo -> FilePath+localGitDir :: Repo -> RawFilePath localGitDir Repo { location = Local { gitdir = d } } = d localGitDir _ = error "unknown localGitDir" @@ -132,16 +132,17 @@ attributes :: Repo -> FilePath attributes repo 	| repoIsLocalBare repo = attributesLocal repo-	| otherwise = repoPath repo </> ".gitattributes"+	| otherwise = fromRawFilePath (repoPath repo) </> ".gitattributes"  attributesLocal :: Repo -> FilePath-attributesLocal repo = localGitDir repo </> "info" </> "attributes"+attributesLocal repo = fromRawFilePath (localGitDir repo)+	</> "info" </> "attributes"  {- Path to a given hook script in a repository, only if the hook exists  - and is executable. -} hookPath :: String -> Repo -> IO (Maybe FilePath) hookPath script repo = do-	let hook = localGitDir repo </> "hooks" </> script+	let hook = fromRawFilePath (localGitDir repo) </> "hooks" </> script 	ifM (catchBoolIO $ isexecutable hook) 		( return $ Just hook , return Nothing )   where@@ -157,22 +158,22 @@   where 	torel p = do 		p' <- relPathCwdToFile p-		if null p'-			then return "."-			else return p'+		return $ if null p' then "." else p'  {- Adusts the path to a local Repo using the provided function. -} adjustPath :: (FilePath -> IO FilePath) -> Repo -> IO Repo adjustPath f r@(Repo { location = l@(Local { gitdir = d, worktree = w }) }) = do-	d' <- f d-	w' <- maybe (pure Nothing) (Just <$$> f) w+	d' <- f' d+	w' <- maybe (pure Nothing) (Just <$$> f') w 	return $ r  		{ location = l  			{ gitdir = d' 			, worktree = w' 			} 		}+  where+	f' v = toRawFilePath <$> f (fromRawFilePath v) adjustPath f r@(Repo { location = LocalUnknown d }) = do-	d' <- f d+	d' <- toRawFilePath <$> f (fromRawFilePath d) 	return $ r { location = LocalUnknown d' } adjustPath _ r = pure r
Git/AutoCorrect.hs view
@@ -5,6 +5,8 @@  - Licensed under the GNU AGPL version 3 or higher.  -} +{-# LANGUAGE OverloadedStrings #-}+ module Git.AutoCorrect where  import Common@@ -44,7 +46,7 @@  -} prepare :: String -> (c -> String) -> [c] -> Maybe Repo -> IO () prepare input showmatch matches r =-	case readish . Git.Config.get "help.autocorrect" "0" =<< r of+	case readish . fromConfigValue . Git.Config.get "help.autocorrect" "0" =<< r of 		Just n 			| n == 0 -> list 			| n < 0 -> warn Nothing
Git/Branch.hs view
@@ -6,6 +6,7 @@  -}  {-# LANGUAGE BangPatterns #-}+{-# LANGUAGE OverloadedStrings #-}  module Git.Branch where @@ -16,6 +17,8 @@ import qualified Git.Config import qualified Git.Ref +import qualified Data.ByteString as B+ {- The currently checked out branch.  -  - In a just initialized git repo before the first commit,@@ -29,19 +32,19 @@ 	case v of 		Nothing -> return Nothing 		Just branch -> -			ifM (null <$> pipeReadStrict [Param "show-ref", Param $ fromRef branch] r)+			ifM (B.null <$> pipeReadStrict [Param "show-ref", Param $ fromRef branch] r) 				( return Nothing 				, return v 				)  {- The current branch, which may not really exist yet. -} currentUnsafe :: Repo -> IO (Maybe Branch)-currentUnsafe r = parse . firstLine+currentUnsafe r = parse . firstLine' 	<$> pipeReadStrict [Param "symbolic-ref", Param "-q", Param $ fromRef Git.Ref.headRef] r   where-	parse l-		| null l = Nothing-		| otherwise = Just $ Git.Ref l+	parse b+		| B.null b = Nothing+		| otherwise = Just $ Git.Ref $ decodeBS b  {- Checks if the second branch has any commits not present on the first  - branch. -}@@ -53,7 +56,8 @@   where  changed' :: Branch -> Branch -> [CommandParam] -> Repo -> IO String-changed' origbranch newbranch extraps repo = pipeReadStrict ps repo+changed' origbranch newbranch extraps repo =+	decodeBS <$> pipeReadStrict ps repo   where 	ps = 		[ Param "log"@@ -72,7 +76,7 @@  -  - This requires there to be a path from the old to the new. -} fastForwardable :: Ref -> Ref -> Repo -> IO Bool-fastForwardable old new repo = not . null <$>+fastForwardable old new repo = not . B.null <$> 	pipeReadStrict 		[ Param "log" 		, Param $ fromRef old ++ ".." ++ fromRef new@@ -132,8 +136,8 @@ applyCommitModeForCommitTree :: CommitMode -> [CommandParam] -> Repo -> [CommandParam] applyCommitModeForCommitTree commitmode ps r 	| commitmode == ManualCommit =-		case (Git.Config.getMaybe "commit.gpgsign" r) of-			Just s | Git.Config.isTrue s == Just True ->+		case Git.Config.getMaybe "commit.gpgsign" r of+			Just s | Git.Config.isTrueFalse' s == Just True -> 				Param "-S":ps 			_ -> ps' 	| otherwise = ps'@@ -160,7 +164,7 @@ commit :: CommitMode -> Bool -> String -> Branch -> [Ref] -> Repo -> IO (Maybe Sha) commit commitmode allowempty message branch parentrefs repo = do 	tree <- getSha "write-tree" $-		pipeReadStrict [Param "write-tree"] repo+		decodeBS' <$> pipeReadStrict [Param "write-tree"] repo 	ifM (cancommit tree) 		( do 			sha <- commitTree commitmode message parentrefs tree repo
Git/CatFile.hs view
@@ -1,6 +1,6 @@ {- git cat-file interface  -- - Copyright 2011-2018 Joey Hess <id@joeyh.name>+ - Copyright 2011-2019 Joey Hess <id@joeyh.name>  -  - Licensed under the GNU AGPL version 3 or higher.  -}@@ -33,6 +33,7 @@ import Common import Git import Git.Sha+import qualified Git.Ref import Git.Command import Git.Types import Git.FilePath@@ -66,13 +67,13 @@ 	CoProcess.stop (checkFileProcess h)  {- Reads a file from a specified branch. -}-catFile :: CatFileHandle -> Branch -> FilePath -> IO L.ByteString+catFile :: CatFileHandle -> Branch -> RawFilePath -> IO L.ByteString catFile h branch file = catObject h $ Ref $-	fromRef branch ++ ":" ++ toInternalGitPath file+	fromRef branch ++ ":" ++ fromRawFilePath (toInternalGitPath file) -catFileDetails :: CatFileHandle -> Branch -> FilePath -> IO (Maybe (L.ByteString, Sha, ObjectType))+catFileDetails :: CatFileHandle -> Branch -> RawFilePath -> IO (Maybe (L.ByteString, Sha, ObjectType)) catFileDetails h branch file = catObjectDetails h $ Ref $-	fromRef branch ++ ":" ++ toInternalGitPath file+	fromRef branch ++ ":" ++ fromRawFilePath (toInternalGitPath file)  {- Uses a running git cat-file read the content of an object.  - Objects that do not exist will have "" returned. -}@@ -109,22 +110,23 @@ 				return (Just (content, sha, objtype))  {- Gets the size and type of an object, without reading its content. -}-catObjectMetaData :: CatFileHandle -> Ref -> IO (Maybe (Integer, ObjectType))+catObjectMetaData :: CatFileHandle -> Ref -> IO (Maybe (Sha, FileSize, ObjectType)) catObjectMetaData h object = query (checkFileProcess h) object newlinefallback $ \from -> do 	resp <- hGetLine from 	case parseResp object resp of-		Just (ParsedResp _ size objtype) ->-			return $ Just (size, objtype)+		Just (ParsedResp sha size objtype) ->+			return $ Just (sha, size, objtype) 		Just DNE -> return Nothing 		Nothing -> error $ "unknown response from git cat-file " ++ show (resp, object)   where 	-- Slow fallback path for filenames containing newlines. 	newlinefallback = do+		sha <- Git.Ref.sha object (gitRepo h) 		sz <- querySize object (gitRepo h) 		objtype <- queryObjectType object (gitRepo h)-		return $ (,) <$> sz <*> objtype+		return $ (,,) <$> sha <*> sz <*> objtype -data ParsedResp = ParsedResp Sha Integer ObjectType | DNE+data ParsedResp = ParsedResp Sha FileSize ObjectType | DNE  query :: CoProcess.CoProcessHandle -> Ref -> IO a -> (Handle -> IO a) -> IO a query hdl object newlinefallback receive@@ -148,7 +150,7 @@ 	| otherwise = case words l of 		[sha, objtype, size] 			| length sha == shaSize ->-				case (readObjectType objtype, reads size) of+				case (readObjectType (encodeBS objtype), reads size) of 					(Just t, [(bytes, "")]) ->  						Just $ ParsedResp (Ref sha) bytes t 					_ -> Nothing@@ -180,12 +182,12 @@ 			, return Nothing 			) -querySize :: Ref -> Repo -> IO (Maybe Integer)+querySize :: Ref -> Repo -> IO (Maybe FileSize) querySize r repo = maybe Nothing (readMaybe . takeWhile (/= '\n')) 	<$> querySingle (Param "-s") r repo hGetContentsStrict  queryObjectType :: Ref -> Repo -> IO (Maybe ObjectType)-queryObjectType r repo = maybe Nothing (readObjectType . takeWhile (/= '\n'))+queryObjectType r repo = maybe Nothing (readObjectType . encodeBS . takeWhile (/= '\n')) 	<$> querySingle (Param "-t") r repo hGetContentsStrict  queryContent :: Ref -> Repo -> IO (Maybe L.ByteString)
Git/Command.hs view
@@ -14,6 +14,9 @@ import Git.Types import qualified Utility.CoProcess as CoProcess +import qualified Data.ByteString.Lazy as L+import qualified Data.ByteString as S+ {- Constructs a git command line operating on the specified repo. -} gitCommandLine :: [CommandParam] -> Repo -> [CommandParam] gitCommandLine params r@(Repo { location = l@(Local { } ) }) =@@ -21,10 +24,10 @@   where 	setdir 		| gitEnvOverridesGitDir r = []-		| otherwise = [Param $ "--git-dir=" ++ gitdir l]+		| otherwise = [Param $ "--git-dir=" ++ fromRawFilePath (gitdir l)] 	settree = case worktree l of 		Nothing -> []-		Just t -> [Param $ "--work-tree=" ++ t]+		Just t -> [Param $ "--work-tree=" ++ fromRawFilePath t] gitCommandLine _ repo = assertLocal repo $ error "internal"  {- Runs git in the specified repo. -}@@ -50,10 +53,10 @@  - read, that will wait on the command, and  - return True if it succeeded. Failure to wait will result in zombies.  -}-pipeReadLazy :: [CommandParam] -> Repo -> IO (String, IO Bool)+pipeReadLazy :: [CommandParam] -> Repo -> IO (L.ByteString, IO Bool) pipeReadLazy params repo = assertLocal repo $ do 	(_, Just h, _, pid) <- createProcess p { std_out = CreatePipe }-	c <- hGetContents h+	c <- L.hGetContents h 	return (c, checkSuccessProcess pid)   where 	p  = gitCreateProcess params repo@@ -62,8 +65,8 @@  -  - Nonzero exit status is ignored.  -}-pipeReadStrict :: [CommandParam] -> Repo -> IO String-pipeReadStrict = pipeReadStrict' hGetContentsStrict+pipeReadStrict :: [CommandParam] -> Repo -> IO S.ByteString+pipeReadStrict = pipeReadStrict' S.hGetContents  {- The reader action must be strict. -} pipeReadStrict' :: (Handle -> IO a) -> [CommandParam] -> Repo -> IO a@@ -93,22 +96,29 @@  {- Reads null terminated output of a git command (as enabled by the -z   - parameter), and splits it. -}-pipeNullSplit :: [CommandParam] -> Repo -> IO ([String], IO Bool)+pipeNullSplit :: [CommandParam] -> Repo -> IO ([L.ByteString], IO Bool) pipeNullSplit params repo = do 	(s, cleanup) <- pipeReadLazy params repo-	return (filter (not . null) $ splitc sep s, cleanup)-  where-	sep = '\0'+	return (filter (not . L.null) $ L.split 0 s, cleanup) -pipeNullSplitStrict :: [CommandParam] -> Repo -> IO [String]+{- Reads lazily, but copies each part to a strict ByteString for+ - convenience.+ -}+pipeNullSplit' :: [CommandParam] -> Repo -> IO ([S.ByteString], IO Bool)+pipeNullSplit' params repo = do+	(s, cleanup) <- pipeNullSplit params repo+	return (map L.toStrict s, cleanup)++pipeNullSplitStrict :: [CommandParam] -> Repo -> IO [S.ByteString] pipeNullSplitStrict params repo = do 	s <- pipeReadStrict params repo-	return $ filter (not . null) $ splitc sep s-  where-	sep = '\0'+	return $ filter (not . S.null) $ S.split 0 s -pipeNullSplitZombie :: [CommandParam] -> Repo -> IO [String]+pipeNullSplitZombie :: [CommandParam] -> Repo -> IO [L.ByteString] pipeNullSplitZombie params repo = leaveZombie <$> pipeNullSplit params repo++pipeNullSplitZombie' :: [CommandParam] -> Repo -> IO [S.ByteString]+pipeNullSplitZombie' params repo = leaveZombie <$> pipeNullSplit' params repo  {- Doesn't run the cleanup action. A zombie results. -} leaveZombie :: (a, IO Bool) -> a
Git/Config.hs view
@@ -1,14 +1,19 @@ {- git repository configuration handling  -- - Copyright 2010-2012 Joey Hess <id@joeyh.name>+ - Copyright 2010-2019 Joey Hess <id@joeyh.name>  -  - Licensed under the GNU AGPL version 3 or higher.  -} +{-# LANGUAGE OverloadedStrings #-}+ module Git.Config where  import qualified Data.Map as M+import qualified Data.ByteString as S+import qualified Data.ByteString.Char8 as S8 import Data.Char+import qualified System.FilePath.ByteString as P  import Common import Git@@ -17,16 +22,16 @@ import qualified Git.Construct import Utility.UserInfo -{- Returns a single git config setting, or a default value if not set. -}-get :: String -> String -> Repo -> String-get key defaultValue repo = M.findWithDefault defaultValue key (config repo)+{- Returns a single git config setting, or a fallback value if not set. -}+get :: ConfigKey -> ConfigValue -> Repo -> ConfigValue+get key fallback repo = M.findWithDefault fallback key (config repo) -{- Returns a list with each line of a multiline config setting. -}-getList :: String -> Repo -> [String]+{- Returns a list of values. -}+getList :: ConfigKey -> Repo -> [ConfigValue] getList key repo = M.findWithDefault [] key (fullconfig repo)  {- Returns a single git config setting, if set. -}-getMaybe :: String -> Repo -> Maybe String+getMaybe :: ConfigKey -> Repo -> Maybe ConfigValue getMaybe key repo = M.lookup key (config repo)  {- Runs git config and populates a repo with its config.@@ -57,7 +62,7 @@ 	  where 		params = ["config", "--null", "--list"] 		p = (proc "git" params)-			{ cwd = Just d+			{ cwd = Just (fromRawFilePath d) 			, env = gitEnv repo 			} @@ -79,14 +84,14 @@ {- Reads git config from a handle and populates a repo with it. -} hRead :: Repo -> Handle -> IO Repo hRead repo h = do-	val <- hGetContentsStrict h+	val <- S.hGetContents h 	store val repo  {- Stores a git config into a Repo, returning the new version of the Repo.  - The git config may be multiple lines, or a single line.  - Config settings can be updated incrementally.  -}-store :: String -> Repo -> IO Repo+store :: S.ByteString -> Repo -> IO Repo store s repo = do 	let c = parse s 	updateLocation $ repo@@ -96,7 +101,7 @@  {- Stores a single config setting in a Repo, returning the new version of  - the Repo. Config settings can be updated incrementally. -}-store' :: String -> String -> Repo -> Repo+store' :: ConfigKey -> ConfigValue -> Repo -> Repo store' k v repo = repo 	{ config = M.singleton k v `M.union` config repo 	, fullconfig = M.unionWith (++) (M.singleton k [v]) (fullconfig repo)@@ -110,13 +115,13 @@  -} updateLocation :: Repo -> IO Repo updateLocation r@(Repo { location = LocalUnknown d })-	| isBare r = ifM (doesDirectoryExist dotgit)+	| isBare r = ifM (doesDirectoryExist (fromRawFilePath dotgit)) 			( updateLocation' r $ Local dotgit Nothing 			, updateLocation' r $ Local d Nothing 			) 	| otherwise = updateLocation' r $ Local dotgit (Just d)   where-	dotgit = (d </> ".git")+	dotgit = d P.</> ".git" updateLocation r@(Repo { location = l@(Local {}) }) = updateLocation' r l updateLocation r = return r @@ -124,52 +129,66 @@ updateLocation' r l = do 	l' <- case getMaybe "core.worktree" r of 		Nothing -> return l-		Just d -> do+		Just (ConfigValue d) -> do 			{- core.worktree is relative to the gitdir -}-			top <- absPath $ gitdir l-			return $ l { worktree = Just $ absPathFrom top d }+			top <- absPath $ fromRawFilePath (gitdir l)+			let p = absPathFrom top (fromRawFilePath d)+			return $ l { worktree = Just (toRawFilePath p) } 	return $ r { location = l' }  {- Parses git config --list or git config --null --list output into a  - config map. -}-parse :: String -> M.Map String [String]-parse [] = M.empty+parse :: S.ByteString -> M.Map ConfigKey [ConfigValue] parse s-	-- --list output will have an = in the first line-	| all ('=' `elem`) (take 1 ls) = sep '=' ls+	| S.null s = M.empty+	-- --list output will have a '=' in the first line+	-- (The first line of --null --list output is the name of a key,+	-- which is assumed to never contain '='.)+	| S.elem eq firstline = sep eq $ S.split nl s 	-- --null --list output separates keys from values with newlines-	| otherwise = sep '\n' $ splitc '\0' s+	| otherwise = sep nl $ S.split 0 s   where-	ls = lines s-	sep c = M.fromListWith (++) . map (\(k,v) -> (k, [v])) .-		map (separate (== c))+	nl = fromIntegral (ord '\n')+	eq = fromIntegral (ord '=')+	firstline = S.takeWhile (/= nl) s -{- Checks if a string from git config is a true value. -}-isTrue :: String -> Maybe Bool-isTrue s+	sep c = M.fromListWith (++)+		. map (\(k,v) -> (ConfigKey k, [ConfigValue (S.drop 1 v)])) +		. map (S.break (== c))++{- Checks if a string from git config is a true/false value. -}+isTrueFalse :: String -> Maybe Bool+isTrueFalse = isTrueFalse' . ConfigValue . encodeBS'++isTrueFalse' :: ConfigValue -> Maybe Bool+isTrueFalse' (ConfigValue s) 	| s' == "true" = Just True 	| s' == "false" = Just False 	| otherwise = Nothing   where-	s' = map toLower s+	s' = S8.map toLower s  boolConfig :: Bool -> String boolConfig True = "true" boolConfig False = "false" +boolConfig' :: Bool -> S.ByteString+boolConfig' True = "true"+boolConfig' False = "false"+ isBare :: Repo -> Bool-isBare r = fromMaybe False $ isTrue =<< getMaybe coreBare r+isBare r = fromMaybe False $ isTrueFalse' =<< getMaybe coreBare r -coreBare :: String+coreBare :: ConfigKey coreBare = "core.bare"  {- Runs a command to get the configuration of a repo,  - and returns a repo populated with the configuration, as well as the raw  - output of the command. -}-fromPipe :: Repo -> String -> [CommandParam] -> IO (Either SomeException (Repo, String))+fromPipe :: Repo -> String -> [CommandParam] -> IO (Either SomeException (Repo, S.ByteString)) fromPipe r cmd params = try $ 	withHandle StdoutHandle createProcessSuccess p $ \h -> do-		val <- hGetContentsStrict h+		val <- S.hGetContents h 		r' <- store val r 		return (r', val)   where@@ -177,7 +196,7 @@  {- Reads git config from a specified file and returns the repo populated  - with the configuration. -}-fromFile :: Repo -> FilePath -> IO (Either SomeException (Repo, String))+fromFile :: Repo -> FilePath -> IO (Either SomeException (Repo, S.ByteString)) fromFile r f = fromPipe r "git" 	[ Param "config" 	, Param "--file"@@ -187,13 +206,13 @@  {- Changes a git config setting in the specified config file.  - (Creates the file if it does not already exist.) -}-changeFile :: FilePath -> String -> String -> IO Bool-changeFile f k v = boolSystem "git"+changeFile :: FilePath -> ConfigKey -> S.ByteString -> IO Bool+changeFile f (ConfigKey k) v = boolSystem "git" 	[ Param "config" 	, Param "--file" 	, File f-	, Param k-	, Param v+	, Param (decodeBS' k)+	, Param (decodeBS' v) 	]  {- Unsets a git config setting, in both the git repo,@@ -202,10 +221,10 @@  - If unsetting the config fails, including in a read-only repo, or  - when the config is not set, returns Nothing.  -}-unset :: String -> Repo -> IO (Maybe Repo)-unset k r = ifM (Git.Command.runBool ps r)-	( return $ Just $ r { config = M.delete k (config r) }+unset :: ConfigKey -> Repo -> IO (Maybe Repo)+unset ck@(ConfigKey k) r = ifM (Git.Command.runBool ps r)+	( return $ Just $ r { config = M.delete ck (config r) } 	, return Nothing 	)   where-	ps = [Param "config", Param "--unset-all", Param k]+	ps = [Param "config", Param "--unset-all", Param (decodeBS' k)]
Git/ConfigTypes.hs view
@@ -5,12 +5,16 @@  - Licensed under the GNU AGPL version 3 or higher.  -} +{-# LANGUAGE OverloadedStrings #-}+ module Git.ConfigTypes where  import Data.Char+import qualified Data.ByteString.Char8 as S8  import Common import Git+import Git.Types import qualified Git.Config  data SharedRepository = UnShared | GroupShared | AllShared | UmaskShared Int@@ -18,23 +22,27 @@  getSharedRepository :: Repo -> SharedRepository getSharedRepository r =-	case map toLower $ Git.Config.get "core.sharedrepository" "" r of-		"1" -> GroupShared-		"2" -> AllShared-		"group" -> GroupShared-		"true" -> GroupShared-		"all" -> AllShared-		"world" -> AllShared-		"everybody" -> AllShared-		v -> maybe UnShared UmaskShared (readish v)+	case Git.Config.getMaybe "core.sharedrepository" r of+		Nothing -> UnShared+		Just (ConfigValue v) -> case S8.map toLower v of+			"1" -> GroupShared+			"2" -> AllShared+			"group" -> GroupShared+			"true" -> GroupShared+			"all" -> AllShared+			"world" -> AllShared+			"everybody" -> AllShared+			_ -> maybe UnShared UmaskShared (readish (decodeBS' v))  data DenyCurrentBranch = UpdateInstead | RefusePush | WarnPush | IgnorePush 	deriving (Eq)  getDenyCurrentBranch :: Repo -> DenyCurrentBranch-getDenyCurrentBranch r =-	case map toLower $ Git.Config.get "receive.denycurrentbranch" "" r of-		"updateinstead" -> UpdateInstead-		"warn" -> WarnPush-		"ignore" -> IgnorePush-		_ -> RefusePush+getDenyCurrentBranch r = +	case Git.Config.getMaybe "receive.denycurrentbranch" r of+		Just (ConfigValue v) -> case S8.map toLower v of+			"updateinstead" -> UpdateInstead+			"warn" -> WarnPush+			"ignore" -> IgnorePush+			_ -> RefusePush+		Nothing -> RefusePush
Git/Construct.hs view
@@ -58,11 +58,11 @@  - specified. -} fromAbsPath :: FilePath -> IO Repo fromAbsPath dir-	| absoluteGitPath dir = hunt+	| absoluteGitPath (encodeBS dir) = hunt 	| otherwise = 		error $ "internal error, " ++ dir ++ " is not absolute"   where-	ret = pure . newFrom . LocalUnknown+	ret = pure . newFrom . LocalUnknown . toRawFilePath 	canondir = dropTrailingPathSeparator dir 	{- When dir == "foo/.git", git looks for "foo/.git/.git", 	 - and failing that, uses "foo" as the repository. -}@@ -117,7 +117,7 @@ 				[ Url.scheme reference 				, "//" 				, auth-				, repoPath r+				, fromRawFilePath (repoPath r) 				] 			in r { location = Url $ fromJust $ parseURI absurl } @@ -128,7 +128,7 @@ 	filterconfig f = filter f $ M.toList $ config repo 	filterkeys f = filterconfig (\(k,_) -> f k) 	remotepairs = filterkeys isRemoteKey-	construct (k,v) = remoteNamedFromKey k $ fromRemoteLocation v repo+	construct (k,v) = remoteNamedFromKey k (fromRemoteLocation (fromConfigValue v) repo)  {- Sets the name of a remote when constructing the Repo to represent it. -} remoteNamed :: String -> IO Repo -> IO Repo@@ -138,7 +138,7 @@  {- Sets the name of a remote based on the git config key, such as  - "remote.foo.url". -}-remoteNamedFromKey :: String -> IO Repo -> IO Repo+remoteNamedFromKey :: ConfigKey -> IO Repo -> IO Repo remoteNamedFromKey = remoteNamed . remoteKeyToRemoteName  {- Constructs a new Repo for one of a Repo's remotes using a given@@ -154,7 +154,7 @@ fromRemotePath :: FilePath -> Repo -> IO Repo fromRemotePath dir repo = do 	dir' <- expandTilde dir-	fromPath $ repoPath repo </> dir'+	fromPath $ fromRawFilePath (repoPath repo) </> dir'  {- Git remotes can have a directory that is specified relative  - to the user's home directory, or that contains tilde expansions.@@ -204,7 +204,7 @@   where 	check test cont = maybe cont (return . Just) =<< test 	checkdir c = ifM c-		( return $ Just $ LocalUnknown dir+		( return $ Just $ LocalUnknown $ toRawFilePath dir 		, return Nothing 		) 	isRepo = checkdir $ @@ -224,9 +224,9 @@ 			catchDefaultIO "" (readFile $ dir </> ".git") 		return $ if gitdirprefix `isPrefixOf` c 			then Just $ Local -				{ gitdir = absPathFrom dir $+				{ gitdir = toRawFilePath $ absPathFrom dir $ 					drop (length gitdirprefix) c-				, worktree = Just dir+				, worktree = Just (toRawFilePath dir) 				} 			else Nothing 	  where
Git/CurrentRepo.hs view
@@ -37,7 +37,7 @@ 	gd <- getpathenv "GIT_DIR" 	r <- configure gd =<< fromCwd 	prefix <- getpathenv "GIT_PREFIX"-	wt <- maybe (worktree $ location r) Just+	wt <- maybe (fromRawFilePath <$> worktree (location r)) Just 		<$> getpathenvprefix "GIT_WORK_TREE" prefix 	case wt of 		Nothing -> return r@@ -68,13 +68,18 @@ 		absd <- absPath d 		curr <- getCurrentDirectory 		r <- Git.Config.read $ newFrom $-			Local { gitdir = absd, worktree = Just curr }+			Local+				{ gitdir = toRawFilePath absd+				, worktree = Just (toRawFilePath curr)+				} 		return $ if Git.Config.isBare r 			then r { location = (location r) { worktree = Nothing } } 			else r  	configure Nothing Nothing = giveup "Not in a git repository." -	addworktree w r = changelocation r $-		Local { gitdir = gitdir (location r), worktree = w }+	addworktree w r = changelocation r $ Local+		{ gitdir = gitdir (location r)+		, worktree = fmap toRawFilePath w+		} 	changelocation r l = r { location = l }
Git/DiffTree.hs view
@@ -31,9 +31,9 @@ {- Checks if the DiffTreeItem modifies a file with a given name  - or under a directory by that name. -} isDiffOf :: DiffTreeItem -> TopFilePath -> Bool-isDiffOf diff f = case getTopFilePath f of+isDiffOf diff f = case fromRawFilePath (getTopFilePath f) of 	"" -> True -- top of repo contains all-	d -> d `dirContains` getTopFilePath (file diff)+	d -> d `dirContains` fromRawFilePath (getTopFilePath (file diff))  {- Diffs two tree Refs. -} diffTree :: Ref -> Ref -> Repo -> IO ([DiffTreeItem], IO Bool)@@ -89,7 +89,7 @@ getdiff :: CommandParam -> [CommandParam] -> Repo -> IO ([DiffTreeItem], IO Bool) getdiff command params repo = do 	(diff, cleanup) <- pipeNullSplit ps repo-	return (parseDiffRaw diff, cleanup)+	return (parseDiffRaw (map decodeBL diff), cleanup)   where 	ps =  		command :@@ -113,7 +113,7 @@ 		, srcsha = fromMaybe (error "bad srcsha") $ extractSha ssha 		, dstsha = fromMaybe (error "bad dstsha") $ extractSha dsha 		, status = s-		, file = asTopFilePath $ fromInternalGitPath $ Git.Filename.decode f+		, file = asTopFilePath $ fromInternalGitPath $ Git.Filename.decode $ toRawFilePath f 		} 	  where 		readmode = fst . Prelude.head . readOct
Git/Env.hs view
@@ -30,8 +30,10 @@  - and a copy of the rest of the system environment. -} propGitEnv :: Repo -> IO [(String, String)] propGitEnv g = do-	g' <- addGitEnv g "GIT_DIR" (localGitDir g)-	g'' <- maybe (pure g') (addGitEnv g' "GIT_WORK_TREE") (repoWorkTree g)+	g' <- addGitEnv g "GIT_DIR" (fromRawFilePath (localGitDir g))+	g'' <- maybe (pure g')+		(addGitEnv g' "GIT_WORK_TREE" . fromRawFilePath)+		(repoWorkTree g) 	return $ fromMaybe [] (gitEnv g'')  {- Use with any action that makes a commit to set metadata. -}
Git/FilePath.hs view
@@ -5,13 +5,14 @@  - top of the repository even when run in a subdirectory. Adding some  - types helps keep that straight.  -- - Copyright 2012-2013 Joey Hess <id@joeyh.name>+ - Copyright 2012-2019 Joey Hess <id@joeyh.name>  -  - Licensed under the GNU AGPL version 3 or higher.  -}  {-# LANGUAGE CPP #-} {-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE OverloadedStrings #-}  module Git.FilePath ( 	TopFilePath,@@ -30,12 +31,14 @@ import Common import Git -import qualified System.FilePath.Posix+import qualified System.FilePath.ByteString as P+import qualified System.FilePath.Posix.ByteString import GHC.Generics import Control.DeepSeq+import qualified Data.ByteString as S -{- A FilePath, relative to the top of the git repository. -}-newtype TopFilePath = TopFilePath { getTopFilePath :: FilePath }+{- A RawFilePath, relative to the top of the git repository. -}+newtype TopFilePath = TopFilePath { getTopFilePath :: RawFilePath } 	deriving (Show, Eq, Ord, Generic)  instance NFData TopFilePath@@ -45,20 +48,22 @@ 	deriving (Show, Eq, Ord)  {- Git uses the branch:file form to refer to a BranchFilePath -}-descBranchFilePath :: BranchFilePath -> String-descBranchFilePath (BranchFilePath b f) = fromRef b ++ ':' : getTopFilePath f+descBranchFilePath :: BranchFilePath -> S.ByteString+descBranchFilePath (BranchFilePath b f) =+	encodeBS' (fromRef b) <> ":" <> getTopFilePath f  {- Path to a TopFilePath, within the provided git repo. -}-fromTopFilePath :: TopFilePath -> Git.Repo -> FilePath-fromTopFilePath p repo = combine (repoPath repo) (getTopFilePath p)+fromTopFilePath :: TopFilePath -> Git.Repo -> RawFilePath+fromTopFilePath p repo = P.combine (repoPath repo) (getTopFilePath p)  {- The input FilePath can be absolute, or relative to the CWD. -}-toTopFilePath :: FilePath -> Git.Repo -> IO TopFilePath-toTopFilePath file repo = TopFilePath <$> relPathDirToFile (repoPath repo) file+toTopFilePath :: RawFilePath -> Git.Repo -> IO TopFilePath+toTopFilePath file repo = TopFilePath . toRawFilePath+	<$> relPathDirToFile (fromRawFilePath (repoPath repo)) (fromRawFilePath file) -{- The input FilePath must already be relative to the top of the git+{- The input RawFilePath must already be relative to the top of the git  - repository -}-asTopFilePath :: FilePath -> TopFilePath+asTopFilePath :: RawFilePath -> TopFilePath asTopFilePath file = TopFilePath file  {- Git may use a different representation of a path when storing@@ -68,25 +73,25 @@  - despite Windows using '\'.  -  -}-type InternalGitPath = String+type InternalGitPath = RawFilePath -toInternalGitPath :: FilePath -> InternalGitPath+toInternalGitPath :: RawFilePath -> InternalGitPath #ifndef mingw32_HOST_OS toInternalGitPath = id #else-toInternalGitPath = replace "\\" "/"+toInternalGitPath = encodeBS . replace "\\" "/" . decodeBS #endif -fromInternalGitPath :: InternalGitPath -> FilePath+fromInternalGitPath :: InternalGitPath -> RawFilePath #ifndef mingw32_HOST_OS fromInternalGitPath = id #else-fromInternalGitPath = replace "/" "\\"+fromInternalGitPath = encodeBS . replace "/" "\\" . decodeBS #endif  {- isAbsolute on Windows does not think "/foo" or "\foo" is absolute,  - so try posix paths.  -}-absoluteGitPath :: FilePath -> Bool-absoluteGitPath p = isAbsolute p ||-	System.FilePath.Posix.isAbsolute (toInternalGitPath p)+absoluteGitPath :: RawFilePath -> Bool+absoluteGitPath p = P.isAbsolute p ||+	System.FilePath.Posix.ByteString.isAbsolute (toInternalGitPath p)
Git/Filename.hs view
@@ -12,23 +12,44 @@ import Utility.Format (decode_c, encode_c)  import Data.Char+import Data.Word+import qualified Data.ByteString as S -decode :: String -> FilePath-decode [] = []-decode f@(c:s)-	-- encoded strings will be inside double quotes-	| c == '"' && end s == ['"'] = decode_c $ beginning s-	| otherwise = f+-- encoded filenames will be inside double quotes+decode :: S.ByteString -> RawFilePath+decode b = case S.uncons b of+	Nothing -> b+	Just (h, t)+		| h /= q -> b+		| otherwise -> case S.unsnoc t of+			Nothing -> b+			Just (i, l)+				| l /= q -> b+				| otherwise ->+					encodeBS $ decode_c $ decodeBS i+  where+  	q :: Word8+	q = fromIntegral (ord '"')  {- Should not need to use this, except for testing decode. -}-encode :: FilePath -> String-encode s = "\"" ++ encode_c s ++ "\""+encode :: RawFilePath -> S.ByteString+encode s = encodeBS $ "\"" ++ encode_c (decodeBS s) ++ "\"" -{- For quickcheck. - -- - See comment on Utility.Format.prop_encode_c_decode_c_roundtrip for- - why this only tests chars < 256 -}-prop_encode_decode_roundtrip :: String -> Bool-prop_encode_decode_roundtrip s = s' == decode (encode s')+prop_encode_decode_roundtrip :: FilePath -> Bool+prop_encode_decode_roundtrip s = s' ==+	fromRawFilePath (decode (encode (toRawFilePath s')))   where-	s' = filter (\c -> ord c < 256) s+	s' = nonul (nohigh s)+	-- Encoding and then decoding roundtrips only when+	-- the string does not contain high unicode, because eg, +	-- both "\12345" and "\227\128\185" are encoded to+	-- "\343\200\271".+	--+	-- This property papers over the problem, by only+	-- testing ascii+	nohigh = filter isAscii+	-- A String can contain a NUL, but toRawFilePath+	-- truncates on the NUL, which is generally fine+	-- because unix filenames cannot contain NUL.+	-- So the encoding only roundtrips when there is no nul.+	nonul = filter (/= '\NUL')
Git/GCrypt.hs view
@@ -7,6 +7,8 @@  - Licensed under the GNU AGPL version 3 or higher.  -} +{-# LANGUAGE OverloadedStrings #-}+ module Git.GCrypt where  import Common@@ -16,6 +18,8 @@ import qualified Git.Command as Command import Utility.Gpg +import qualified Data.ByteString as S+ urlScheme :: String urlScheme = "gcrypt:" @@ -75,9 +79,9 @@  - which is stored in the repository (in encrypted form)  - and cached in a per-remote gcrypt-id configuration setting. -} remoteRepoId :: Repo -> Maybe RemoteName -> Maybe GCryptId-remoteRepoId = getRemoteConfig "gcrypt-id"+remoteRepoId r n = fromConfigValue <$> getRemoteConfig "gcrypt-id" r n -getRemoteConfig :: String -> Repo -> Maybe RemoteName -> Maybe String+getRemoteConfig :: S.ByteString -> Repo -> Maybe RemoteName -> Maybe ConfigValue getRemoteConfig field repo remotename = do 	n <- remotename 	Config.getMaybe (remoteConfigKey field n) repo@@ -92,18 +96,19 @@ 	]   where 	defaultkey = "gcrypt.participants"-	parse (Just "simple") = []-	parse (Just l) = words l+	parse (Just (ConfigValue "simple")) = []+	parse (Just (ConfigValue b)) = words (decodeBS' b) 	parse Nothing = [] -remoteParticipantConfigKey :: RemoteName -> String+remoteParticipantConfigKey :: RemoteName -> ConfigKey remoteParticipantConfigKey = remoteConfigKey "gcrypt-participants" -remotePublishParticipantConfigKey :: RemoteName -> String+remotePublishParticipantConfigKey :: RemoteName -> ConfigKey remotePublishParticipantConfigKey = remoteConfigKey "gcrypt-publish-participants" -remoteSigningKey :: RemoteName -> String+remoteSigningKey :: RemoteName -> ConfigKey remoteSigningKey = remoteConfigKey "gcrypt-signingkey" -remoteConfigKey :: String -> RemoteName -> String-remoteConfigKey key remotename = "remote." ++ remotename ++ "." ++ key+remoteConfigKey :: S.ByteString -> RemoteName -> ConfigKey+remoteConfigKey key remotename = ConfigKey $+	"remote." <> encodeBS' remotename <> "." <> key
Git/HashObject.hs view
@@ -23,12 +23,12 @@  type HashObjectHandle = CoProcess.CoProcessHandle -hashObjectStart :: Repo -> IO HashObjectHandle-hashObjectStart = gitCoProcessStart True-	[ Param "hash-object"-	, Param "-w"-	, Param "--stdin-paths"-	, Param "--no-filters"+hashObjectStart :: Bool -> Repo -> IO HashObjectHandle+hashObjectStart writeobject = gitCoProcessStart True $ catMaybes+	[ Just (Param "hash-object")+	, if writeobject then Just (Param "-w") else Nothing+	, Just (Param "--stdin-paths")+	, Just (Param "--no-filters") 	]  hashObjectStop :: HashObjectHandle -> IO ()@@ -73,4 +73,4 @@ 	pipeWriteRead (map Param params) (Just writer) repo   where 	subcmd = "hash-object"-	params = [subcmd, "-t", show objtype, "-w", "--stdin", "--no-filters"]+	params = [subcmd, "-t", decodeBS (fmtObjectType objtype), "-w", "--stdin", "--no-filters"]
Git/Hook.hs view
@@ -28,7 +28,7 @@ 	a == b = hookName a == hookName b  hookFile :: Hook -> Repo -> FilePath-hookFile h r = localGitDir r </> "hooks" </> hookName h+hookFile h r = fromRawFilePath (localGitDir r) </> "hooks" </> hookName h  {- Writes a hook. Returns False if the hook already exists with a different  - content. Upgrades old scripts.
Git/Index.hs view
@@ -49,7 +49,7 @@  {- The normal index file. Does not check GIT_INDEX_FILE. -} indexFile :: Repo -> FilePath-indexFile r = localGitDir r </> "index"+indexFile r = fromRawFilePath (localGitDir r) </> "index"  {- The index file git will currently use, checking GIT_INDEX_FILE. -} currentIndexFile :: Repo -> IO FilePath
Git/LsFiles.hs view
@@ -34,37 +34,40 @@  import Numeric import System.Posix.Types+import qualified Data.ByteString.Lazy as L  {- Scans for files that are checked into git's index at the specified locations. -}-inRepo :: [FilePath] -> Repo -> IO ([FilePath], IO Bool)+inRepo :: [RawFilePath] -> Repo -> IO ([RawFilePath], IO Bool) inRepo = inRepo' []  -inRepo' :: [CommandParam] -> [FilePath] -> Repo -> IO ([FilePath], IO Bool)-inRepo' ps l = pipeNullSplit $ -	Param "ls-files" :-	Param "--cached" :-	Param "-z" :-	ps ++-	(Param "--" : map File l)+inRepo' :: [CommandParam] -> [RawFilePath] -> Repo -> IO ([RawFilePath], IO Bool)+inRepo' ps l repo = pipeNullSplit' params repo+  where+	params = +		Param "ls-files" :+		Param "--cached" :+		Param "-z" :+		ps +++		(Param "--" : map (File . fromRawFilePath) l)  {- Files that are checked into the index or have been committed to a  - branch. -}-inRepoOrBranch :: Branch -> [FilePath] -> Repo -> IO ([FilePath], IO Bool)+inRepoOrBranch :: Branch -> [RawFilePath] -> Repo -> IO ([RawFilePath], IO Bool) inRepoOrBranch (Ref b) = inRepo' [Param $ "--with-tree=" ++ b]  {- Scans for files at the specified locations that are not checked into git. -}-notInRepo :: Bool -> [FilePath] -> Repo -> IO ([FilePath], IO Bool)+notInRepo :: Bool -> [RawFilePath] -> Repo -> IO ([RawFilePath], IO Bool) notInRepo = notInRepo' [] -notInRepo' :: [CommandParam] -> Bool -> [FilePath] -> Repo -> IO ([FilePath], IO Bool)-notInRepo' ps include_ignored l repo = pipeNullSplit params repo+notInRepo' :: [CommandParam] -> Bool -> [RawFilePath] -> Repo -> IO ([RawFilePath], IO Bool)+notInRepo' ps include_ignored l repo = pipeNullSplit' params repo   where 	params = concat 		[ [ Param "ls-files", Param "--others"] 		, ps 		, exclude 		, [ Param "-z", Param "--" ]-		, map File l+		, map (File . fromRawFilePath) l 		] 	exclude 		| include_ignored = []@@ -72,48 +75,48 @@  {- Scans for files at the specified locations that are not checked into  - git. Empty directories are included in the result. -}-notInRepoIncludingEmptyDirectories :: Bool -> [FilePath] -> Repo -> IO ([FilePath], IO Bool)+notInRepoIncludingEmptyDirectories :: Bool -> [RawFilePath] -> Repo -> IO ([RawFilePath], IO Bool) notInRepoIncludingEmptyDirectories = notInRepo' [Param "--directory"]  {- Finds all files in the specified locations, whether checked into git or  - not. -}-allFiles :: [FilePath] -> Repo -> IO ([FilePath], IO Bool)-allFiles l = pipeNullSplit $+allFiles :: [RawFilePath] -> Repo -> IO ([RawFilePath], IO Bool)+allFiles l = pipeNullSplit' $ 	Param "ls-files" : 	Param "--cached" : 	Param "--others" : 	Param "-z" : 	Param "--" :-	map File l+	map (File . fromRawFilePath) l  {- Returns a list of files in the specified locations that have been  - deleted. -}-deleted :: [FilePath] -> Repo -> IO ([FilePath], IO Bool)-deleted l repo = pipeNullSplit params repo+deleted :: [RawFilePath] -> Repo -> IO ([RawFilePath], IO Bool)+deleted l repo = pipeNullSplit' params repo   where 	params = 		Param "ls-files" : 		Param "--deleted" : 		Param "-z" : 		Param "--" :-		map File l+		map (File . fromRawFilePath) l  {- Returns a list of files in the specified locations that have been  - modified. -}-modified :: [FilePath] -> Repo -> IO ([FilePath], IO Bool)-modified l repo = pipeNullSplit params repo+modified :: [RawFilePath] -> Repo -> IO ([RawFilePath], IO Bool)+modified l repo = pipeNullSplit' params repo   where 	params =  		Param "ls-files" : 		Param "--modified" : 		Param "-z" : 		Param "--" :-		map File l+		map (File . fromRawFilePath) l  {- Files that have been modified or are not checked into git (and are not  - ignored). -}-modifiedOthers :: [FilePath] -> Repo -> IO ([FilePath], IO Bool)-modifiedOthers l repo = pipeNullSplit params repo+modifiedOthers :: [RawFilePath] -> Repo -> IO ([RawFilePath], IO Bool)+modifiedOthers l repo = pipeNullSplit' params repo   where 	params =  		Param "ls-files" :@@ -122,69 +125,69 @@ 		Param "--exclude-standard" : 		Param "-z" : 		Param "--" :-		map File l+		map (File . fromRawFilePath) l  {- Returns a list of all files that are staged for commit. -}-staged :: [FilePath] -> Repo -> IO ([FilePath], IO Bool)+staged :: [RawFilePath] -> Repo -> IO ([RawFilePath], IO Bool) staged = staged' []  {- Returns a list of the files, staged for commit, that are being added,  - moved, or changed (but not deleted), from the specified locations. -}-stagedNotDeleted :: [FilePath] -> Repo -> IO ([FilePath], IO Bool)+stagedNotDeleted :: [RawFilePath] -> Repo -> IO ([RawFilePath], IO Bool) stagedNotDeleted = staged' [Param "--diff-filter=ACMRT"] -staged' :: [CommandParam] -> [FilePath] -> Repo -> IO ([FilePath], IO Bool)-staged' ps l = pipeNullSplit $ prefix ++ ps ++ suffix+staged' :: [CommandParam] -> [RawFilePath] -> Repo -> IO ([RawFilePath], IO Bool)+staged' ps l repo = pipeNullSplit' (prefix ++ ps ++ suffix) repo   where 	prefix = [Param "diff", Param "--cached", Param "--name-only", Param "-z"]-	suffix = Param "--" : map File l+	suffix = Param "--" : map (File . fromRawFilePath) l -type StagedDetails = (FilePath, Maybe Sha, Maybe FileMode)+type StagedDetails = (RawFilePath, Maybe Sha, Maybe FileMode)  {- Returns details about files that are staged in the index,  - as well as files not yet in git. Skips ignored files. -}-stagedOthersDetails :: [FilePath] -> Repo -> IO ([StagedDetails], IO Bool)+stagedOthersDetails :: [RawFilePath] -> Repo -> IO ([StagedDetails], IO Bool) stagedOthersDetails = stagedDetails' [Param "--others", Param "--exclude-standard"]  {- Returns details about all files that are staged in the index. -}-stagedDetails :: [FilePath] -> Repo -> IO ([StagedDetails], IO Bool)+stagedDetails :: [RawFilePath] -> Repo -> IO ([StagedDetails], IO Bool) stagedDetails = stagedDetails' []  {- Gets details about staged files, including the Sha of their staged  - contents. -}-stagedDetails' :: [CommandParam] -> [FilePath] -> Repo -> IO ([StagedDetails], IO Bool)+stagedDetails' :: [CommandParam] -> [RawFilePath] -> Repo -> IO ([StagedDetails], IO Bool) stagedDetails' ps l repo = do 	(ls, cleanup) <- pipeNullSplit params repo 	return (map parse ls, cleanup)   where 	params = Param "ls-files" : Param "--stage" : Param "-z" : ps ++ -		Param "--" : map File l+		Param "--" : map (File . fromRawFilePath) l 	parse s-		| null file = (s, Nothing, Nothing)-		| otherwise = (file, extractSha $ take shaSize rest, readmode mode)+		| null file = (L.toStrict s, Nothing, Nothing)+		| otherwise = (toRawFilePath file, extractSha $ take shaSize rest, readmode mode) 	  where-		(metadata, file) = separate (== '\t') s+		(metadata, file) = separate (== '\t') (decodeBL' s) 		(mode, rest) = separate (== ' ') metadata 		readmode = fst <$$> headMaybe . readOct  {- Returns a list of the files in the specified locations that are staged  - for commit, and whose type has changed. -}-typeChangedStaged :: [FilePath] -> Repo -> IO ([FilePath], IO Bool)+typeChangedStaged :: [RawFilePath] -> Repo -> IO ([RawFilePath], IO Bool) typeChangedStaged = typeChanged' [Param "--cached"]  {- Returns a list of the files in the specified locations whose type has  - changed.  Files only staged for commit will not be included. -}-typeChanged :: [FilePath] -> Repo -> IO ([FilePath], IO Bool)+typeChanged :: [RawFilePath] -> Repo -> IO ([RawFilePath], IO Bool) typeChanged = typeChanged' [] -typeChanged' :: [CommandParam] -> [FilePath] -> Repo -> IO ([FilePath], IO Bool)+typeChanged' :: [CommandParam] -> [RawFilePath] -> Repo -> IO ([RawFilePath], IO Bool) typeChanged' ps l 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.-	top <- absPath (repoPath repo)+	top <- absPath (fromRawFilePath (repoPath repo)) 	currdir <- getCurrentDirectory-	return (map (\f -> relPathDirToFileAbs currdir $ top </> f) fs, cleanup)+	return (map (\f -> toRawFilePath (relPathDirToFileAbs currdir $ top </> decodeBL' f)) fs, cleanup)   where 	prefix =  		[ Param "diff"@@ -192,7 +195,7 @@ 		, Param "--diff-filter=T" 		, Param "-z" 		]-	suffix = Param "--" : (if null l then [File "."] else map File l)+	suffix = Param "--" : (if null l then [File "."] else map (File . fromRawFilePath) l)  {- A item in conflict has two possible values.  - Either can be Nothing, when that side deleted the file. -}@@ -202,7 +205,7 @@ 	} deriving (Show)  data Unmerged = Unmerged-	{ unmergedFile :: FilePath+	{ unmergedFile :: RawFilePath 	, unmergedTreeItemType :: Conflicting TreeItemType 	, unmergedSha :: Conflicting Sha 	}@@ -217,21 +220,21 @@  -   3 = them  - If a line is omitted, that side removed the file.  -}-unmerged :: [FilePath] -> Repo -> IO ([Unmerged], IO Bool)+unmerged :: [RawFilePath] -> Repo -> IO ([Unmerged], IO Bool) unmerged l repo = do 	(fs, cleanup) <- pipeNullSplit params repo-	return (reduceUnmerged [] $ catMaybes $ map parseUnmerged fs, cleanup)+	return (reduceUnmerged [] $ catMaybes $ map (parseUnmerged . decodeBL') fs, cleanup)   where 	params =  		Param "ls-files" : 		Param "--unmerged" : 		Param "-z" : 		Param "--" :-		map File l+		map (File . fromRawFilePath) l  data InternalUnmerged = InternalUnmerged 	{ isus :: Bool-	, ifile :: FilePath+	, ifile :: RawFilePath 	, itreeitemtype :: Maybe TreeItemType 	, isha :: Maybe Sha 	}@@ -245,9 +248,9 @@ 			if stage /= 2 && stage /= 3 				then Nothing 				else do-					treeitemtype <- readTreeItemType rawtreeitemtype+					treeitemtype <- readTreeItemType (encodeBS rawtreeitemtype) 					sha <- extractSha rawsha-					return $ InternalUnmerged (stage == 2) file+					return $ InternalUnmerged (stage == 2) (toRawFilePath file) 						(Just treeitemtype) (Just sha) 		_ -> Nothing   where
Git/LsTree.hs view
@@ -24,14 +24,19 @@ import Git.Sha import Git.FilePath import qualified Git.Filename+import Utility.Attoparsec  import Numeric-import Data.Char+import Data.Either import System.Posix.Types+import qualified Data.ByteString as S+import qualified Data.ByteString.Lazy as L+import qualified Data.Attoparsec.ByteString.Lazy as A+import qualified Data.Attoparsec.ByteString.Char8 as A8  data TreeItem = TreeItem 	{ mode :: FileMode-	, typeobj :: String+	, typeobj :: S.ByteString 	, sha :: Ref 	, file :: TopFilePath 	} deriving Show@@ -45,7 +50,7 @@ lsTree' :: [CommandParam] -> LsTreeMode -> Ref -> Repo -> IO ([TreeItem], IO Bool) lsTree' ps lsmode t repo = do 	(l, cleanup) <- pipeNullSplit (lsTreeParams lsmode t ps) repo-	return (map parseLsTree l, cleanup)+	return (rights (map parseLsTree l), cleanup)  lsTreeParams :: LsTreeMode -> Ref -> [CommandParam] -> [CommandParam] lsTreeParams lsmode r ps =@@ -63,7 +68,8 @@  {- Lists specified files in a tree. -} lsTreeFiles :: Ref -> [FilePath] -> Repo -> IO [TreeItem]-lsTreeFiles t fs repo = map parseLsTree <$> pipeNullSplitStrict ps repo+lsTreeFiles t fs repo = rights . map (parseLsTree . L.fromStrict)+	<$> pipeNullSplitStrict ps repo   where 	ps = 		[ Param "ls-tree"@@ -73,30 +79,34 @@ 		, File $ fromRef t 		] ++ map File fs +parseLsTree :: L.ByteString -> Either String TreeItem+parseLsTree b = case A.parse parserLsTree b of+	A.Done _ r  -> Right r+	A.Fail _ _ err -> Left err+ {- Parses a line of ls-tree output, in format:  - mode SP type SP sha TAB file  -  - (The --long format is not currently supported.) -}-parseLsTree :: String -> TreeItem-parseLsTree l = TreeItem -	{ mode = smode-	, typeobj = t-	, sha = Ref s-	, file = sfile-	}-  where-	(m, past_m) = splitAt 7 l -- mode is 6 bytes-	(!t, past_t) = separate isSpace past_m-	(!s, past_s) = splitAt shaSize past_t-	!f = drop 1 past_s-	!smode = fst $ Prelude.head $ readOct m-	!sfile = asTopFilePath $ Git.Filename.decode f+parserLsTree :: A.Parser TreeItem+parserLsTree = TreeItem+	-- mode+	<$> octal+	<* A8.char ' '+	-- type+	<*> A.takeTill (== 32)+	<* A8.char ' '+	-- sha+	<*> (Ref . decodeBS' <$> A.take shaSize)+	<* A8.char '\t'+	-- file+	<*> (asTopFilePath . Git.Filename.decode <$> A.takeByteString)  {- Inverse of parseLsTree -} formatLsTree :: TreeItem -> String formatLsTree ti = unwords 	[ showOct (mode ti) ""-	, typeobj ti+	, decodeBS (typeobj ti) 	, fromRef (sha ti)-	, getTopFilePath (file ti)+	, fromRawFilePath (getTopFilePath (file ti)) 	]
Git/Objects.hs view
@@ -12,7 +12,7 @@ import Git.Sha  objectsDir :: Repo -> FilePath-objectsDir r = localGitDir r </> "objects"+objectsDir r = fromRawFilePath (localGitDir r) </> "objects"  packDir :: Repo -> FilePath packDir r = objectsDir r </> "pack"
Git/Ref.hs view
@@ -5,6 +5,8 @@  - Licensed under the GNU AGPL version 3 or higher.  -} +{-# LANGUAGE OverloadedStrings #-}+ module Git.Ref where  import Common@@ -13,13 +15,14 @@ import Git.Sha import Git.Types -import Data.Char (chr)+import Data.Char (chr, ord)+import qualified Data.ByteString as S  headRef :: Ref headRef = Ref "HEAD"  headFile :: Repo -> FilePath-headFile r = localGitDir r </> "HEAD"+headFile r = fromRawFilePath (localGitDir r) </> "HEAD"  setHeadRef :: Ref -> Repo -> IO () setHeadRef ref r = writeFile (headFile r) ("ref: " ++ fromRef ref)@@ -62,8 +65,8 @@  - Prefixing the file with ./ makes this work even if in a subdirectory  - of a repo.  -}-fileRef :: FilePath -> Ref-fileRef f = Ref $ ":./" ++ f+fileRef :: RawFilePath -> Ref+fileRef f = Ref $ ":./" ++ fromRawFilePath f  {- Converts a Ref to refer to the content of the Ref on a given date. -} dateRef :: Ref -> RefDate -> Ref@@ -71,7 +74,7 @@  {- A Ref that can be used to refer to a file in the repository as it  - appears in a given Ref. -}-fileFromRef :: Ref -> FilePath -> Ref+fileFromRef :: Ref -> RawFilePath -> Ref fileFromRef (Ref r) f = let (Ref fr) = fileRef f in Ref (r ++ fr)  {- Checks if a ref exists. -}@@ -82,14 +85,16 @@ {- The file used to record a ref. (Git also stores some refs in a  - packed-refs file.) -} file :: Ref -> Repo -> FilePath-file ref repo = localGitDir repo </> fromRef ref+file ref repo = fromRawFilePath (localGitDir repo) </> fromRef ref  {- Checks if HEAD exists. It generally will, except for in a repository  - that was just created. -} headExists :: Repo -> IO Bool headExists repo = do-	ls <- lines <$> pipeReadStrict [Param "show-ref", Param "--head"] repo-	return $ any (" HEAD" `isSuffixOf`) ls+	ls <- S.split nl <$> pipeReadStrict [Param "show-ref", Param "--head"] repo+	return $ any (" HEAD" `S.isSuffixOf`) ls+  where+	nl = fromIntegral (ord '\n')  {- Get the sha of a fully qualified git ref, if it exists. -} sha :: Branch -> Repo -> IO (Maybe Sha)@@ -100,8 +105,9 @@ 		, Param "--hash" -- get the hash 		, Param $ fromRef branch 		]-	process [] = Nothing-	process s = Just $ Ref $ firstLine s+	process s+		| S.null s = Nothing+		| otherwise = Just $ Ref $ decodeBS' $ firstLine' s  headSha :: Repo -> IO (Maybe Sha) headSha = sha headRef@@ -116,7 +122,7 @@  {- List of (shas, branches) matching a given ref spec. -} matching' :: [String] -> Repo -> IO [(Sha, Branch)]-matching' ps repo = map gen . lines <$> +matching' ps repo = map gen . lines . decodeBS' <$>  	pipeReadStrict (Param "show-ref" : map Param ps) repo   where 	gen l = let (r, b) = separate (== ' ') l@@ -148,7 +154,7 @@  - The ref may be something like a branch name, and it could contain  - ":subdir" if a subtree is wanted. -} tree :: Ref -> Repo -> IO (Maybe Sha)-tree (Ref ref) = extractSha <$$> pipeReadStrict+tree (Ref ref) = extractSha . decodeBS <$$> pipeReadStrict 	[ Param "rev-parse", Param "--verify", Param "--quiet", Param ref' ]   where 	ref' = if ":" `isInfixOf` ref
Git/RefLog.hs view
@@ -21,7 +21,7 @@ getMulti bs = get' (map (Param . fromRef) bs)  get' :: [CommandParam] -> Repo -> IO [Sha]-get' ps = mapMaybe extractSha . lines <$$> pipeReadStrict ps'+get' ps = mapMaybe extractSha . lines . decodeBS <$$> pipeReadStrict ps'   where 	ps' = catMaybes 		[ Just $ Param "log"
Git/Remote.hs view
@@ -6,6 +6,7 @@  -}  {-# LANGUAGE CPP #-}+{-# LANGUAGE OverloadedStrings #-}  module Git.Remote where @@ -15,18 +16,21 @@  import Data.Char import qualified Data.Map as M+import qualified Data.ByteString as S+import qualified Data.ByteString.Char8 as S8 import Network.URI #ifdef mingw32_HOST_OS import Git.FilePath #endif  {- Is a git config key one that specifies the location of a remote? -}-isRemoteKey :: String -> Bool-isRemoteKey k = "remote." `isPrefixOf` k && ".url" `isSuffixOf` k+isRemoteKey :: ConfigKey -> Bool+isRemoteKey (ConfigKey k) = "remote." `S.isPrefixOf` k && ".url" `S.isSuffixOf` k  {- Get a remote's name from the config key that specifies its location. -}-remoteKeyToRemoteName :: String -> RemoteName-remoteKeyToRemoteName k = intercalate "." $ dropFromEnd 1 $ drop 1 $ splitc '.' k+remoteKeyToRemoteName :: ConfigKey -> RemoteName+remoteKeyToRemoteName (ConfigKey k) = decodeBS' $+	S.intercalate "." $ dropFromEnd 1 $ drop 1 $ S8.split '.' k  {- Construct a legal git remote name out of an arbitrary input string.  -@@ -76,16 +80,16 @@ 	-- insteadof config can rewrite remote location 	calcloc l 		| null insteadofs = l-		| otherwise = replacement ++ drop (length bestvalue) l+		| otherwise = replacement ++ drop (S.length bestvalue) l 	  where-		replacement = drop (length prefix) $-			take (length bestkey - length suffix) bestkey-		(bestkey, bestvalue) = maximumBy longestvalue insteadofs+		replacement = decodeBS' $ S.drop (S.length prefix) $+			S.take (S.length bestkey - S.length suffix) bestkey+		(ConfigKey bestkey, ConfigValue bestvalue) = maximumBy longestvalue insteadofs 		longestvalue (_, a) (_, b) = compare b a-		insteadofs = filterconfig $ \(k, v) -> -			prefix `isPrefixOf` k &&-			suffix `isSuffixOf` k &&-			v `isPrefixOf` l+		insteadofs = filterconfig $ \(ConfigKey k, ConfigValue v) -> +			prefix `S.isPrefixOf` k &&+			suffix `S.isSuffixOf` k &&+			v `S.isPrefixOf` encodeBS l 		filterconfig f = filter f $ 			concatMap splitconfigs $ M.toList $ fullconfig repo 		splitconfigs (k, vs) = map (\v -> (k, v)) vs
Git/Repair.hs view
@@ -227,7 +227,7 @@  - Relies on packed refs being exploded before it's called.  -} getAllRefs :: Repo -> IO [Ref]-getAllRefs r = getAllRefs' (localGitDir r </> "refs")+getAllRefs r = getAllRefs' (fromRawFilePath (localGitDir r) </> "refs")  getAllRefs' :: FilePath -> IO [Ref] getAllRefs' refdir = do@@ -245,13 +245,13 @@ 		nukeFile f   where 	makeref (sha, ref) = do-		let dest = localGitDir r </> fromRef ref+		let dest = fromRawFilePath (localGitDir r) </> fromRef ref 		createDirectoryIfMissing True (parentDir dest) 		unlessM (doesFileExist dest) $ 			writeFile dest (fromRef sha)  packedRefsFile :: Repo -> FilePath-packedRefsFile r = localGitDir r </> "packed-refs"+packedRefsFile r = fromRawFilePath (localGitDir r) </> "packed-refs"  parsePacked :: String -> Maybe (Sha, Ref) parsePacked l = case words l of@@ -263,7 +263,7 @@ {- git-branch -d cannot be used to remove a branch that is directly  - pointing to a corrupt commit. -} nukeBranchRef :: Branch -> Repo -> IO ()-nukeBranchRef b r = nukeFile $ localGitDir r </> fromRef b+nukeBranchRef b r = nukeFile $ fromRawFilePath (localGitDir r) </> fromRef b  {- Finds the most recent commit to a branch that does not need any  - of the missing objects. If the input branch is good as-is, returns it.@@ -284,7 +284,7 @@ 				, Param "--format=%H" 				, Param (fromRef branch) 				] r-			let branchshas = catMaybes $ map extractSha ls+			let branchshas = catMaybes $ map (extractSha . decodeBL) ls 			reflogshas <- RefLog.get branch r 			-- XXX Could try a bit harder here, and look 			-- for uncorrupted old commits in branches in the@@ -313,7 +313,7 @@ 			, Param "--format=%H %T" 			, Param (fromRef commit) 			] r-		let committrees = map parse ls+		let committrees = map (parse . decodeBL) ls 		if any isNothing committrees || null committrees 			then do 				void cleanup@@ -342,7 +342,7 @@ 	| S.member treesha missing = return False 	| otherwise = do 		(ls, cleanup) <- pipeNullSplit (LsTree.lsTreeParams LsTree.LsTreeRecursive treesha []) r-		let objshas = map (LsTree.sha . LsTree.parseLsTree) ls+		let objshas = mapMaybe (LsTree.sha <$$> eitherToMaybe . LsTree.parseLsTree) ls 		if any (`S.member` missing) objshas 			then do 				void cleanup@@ -370,7 +370,7 @@ 	length indexcontents `seq` cleanup  missingIndex :: Repo -> IO Bool-missingIndex r = not <$> doesFileExist (localGitDir r </> "index")+missingIndex r = not <$> doesFileExist (fromRawFilePath (localGitDir r) </> "index")  {- Finds missing and ok files staged in the index. -} partitionIndex :: Repo -> IO ([LsFiles.StagedDetails], [LsFiles.StagedDetails], IO Bool)@@ -394,12 +394,12 @@ 			UpdateIndex.streamUpdateIndex r 				=<< (catMaybes <$> mapM reinject good) 		void cleanup-		return $ map fst3 bad+		return $ map (fromRawFilePath . fst3) bad   where 	reinject (file, Just sha, Just mode) = case toTreeItemType mode of 		Nothing -> return Nothing 		Just treeitemtype -> Just <$>-			UpdateIndex.stageFile sha treeitemtype file r+			UpdateIndex.stageFile sha treeitemtype (fromRawFilePath file) r 	reinject _ = return Nothing  newtype GoodCommits = GoodCommits (S.Set Sha)@@ -446,7 +446,7 @@ 		let f = indexFile g 		void $ tryIO $ allowWrite f   where-	headfile = localGitDir g </> "HEAD"+	headfile = fromRawFilePath (localGitDir g) </> "HEAD" 	validhead s = "ref: refs/" `isPrefixOf` s || isJust (extractSha s)  {- Put it all together. -}
Git/Status.hs view
@@ -57,19 +57,19 @@ 					in go (v : c) xs' 		_ -> go c xs -	cparse 'M' f _ = (Just (Modified (asTopFilePath f)), Nothing)-	cparse 'A' f _ = (Just (Added (asTopFilePath f)), Nothing)-	cparse 'D' f _ = (Just (Deleted (asTopFilePath f)), Nothing)-	cparse 'T' f _ = (Just (TypeChanged (asTopFilePath f)), Nothing)-	cparse '?' f _ = (Just (Untracked (asTopFilePath f)), Nothing)+	cparse 'M' f _ = (Just (Modified (asTopFilePath (toRawFilePath f))), Nothing)+	cparse 'A' f _ = (Just (Added (asTopFilePath (toRawFilePath f))), Nothing)+	cparse 'D' f _ = (Just (Deleted (asTopFilePath (toRawFilePath f))), Nothing)+	cparse 'T' f _ = (Just (TypeChanged (asTopFilePath (toRawFilePath f))), Nothing)+	cparse '?' f _ = (Just (Untracked (asTopFilePath (toRawFilePath f))), Nothing) 	cparse 'R' f (oldf:xs) =-		(Just (Renamed (asTopFilePath oldf) (asTopFilePath f)), Just xs)+		(Just (Renamed (asTopFilePath (toRawFilePath oldf)) (asTopFilePath (toRawFilePath f))), Just xs) 	cparse _ _ _ = (Nothing, Nothing)  getStatus :: [CommandParam] -> [FilePath] -> Repo -> IO ([StagedUnstaged Status], IO Bool) getStatus ps fs r = do 	(ls, cleanup) <- pipeNullSplit ps' r-	return (parseStatusZ ls, cleanup)+	return (parseStatusZ (map decodeBL ls), cleanup)   where 	ps' = concat 		[ [Param "status"]
Git/Tree.hs view
@@ -115,11 +115,11 @@ mkTreeOutput fm ot s f = concat 	[ showOct fm "" 	, " "-	, show ot+	, decodeBS (fmtObjectType ot) 	, " " 	, fromRef s 	, "\t"-	, takeFileName (getTopFilePath f)+	, takeFileName (fromRawFilePath (getTopFilePath f)) 	, "\NUL" 	] @@ -134,7 +134,7 @@ treeItemToLsTreeItem :: TreeItem -> LsTree.TreeItem treeItemToLsTreeItem (TreeItem f mode sha) = LsTree.TreeItem 	{ LsTree.mode = mode-	, LsTree.typeobj = show BlobObject+	, LsTree.typeobj = fmtObjectType BlobObject 	, LsTree.sha = sha 	, LsTree.file = f 	}@@ -156,7 +156,7 @@ 			Just (NewSubTree d l) -> 				go (addsubtree idir m (NewSubTree d (c:l))) is 			_ ->-				go (addsubtree idir m (NewSubTree (asTopFilePath idir) [c])) is+				go (addsubtree idir m (NewSubTree (asTopFilePath (toRawFilePath idir)) [c])) is 	  where 		p = gitPath i 		idir = takeDirectory p@@ -169,7 +169,7 @@ 				Just (NewSubTree d' l) -> 					let l' = filter (\ti -> gitPath ti /= d) l 					in addsubtree parent m' (NewSubTree d' (t:l'))-				_ -> addsubtree parent m' (NewSubTree (asTopFilePath parent) [t])+				_ -> addsubtree parent m' (NewSubTree (asTopFilePath (toRawFilePath parent)) [t]) 		| otherwise = M.insert d t m 	  where 		parent = takeDirectory d@@ -239,7 +239,7 @@ 			Just CommitObject -> do 				let ti = TreeCommit (LsTree.file i) (LsTree.mode i) (LsTree.sha i) 				go h wasmodified (ti:c) depth intree is-			_ -> error ("unexpected object type \"" ++ LsTree.typeobj i ++ "\"")+			_ -> error ("unexpected object type \"" ++ decodeBS (LsTree.typeobj i) ++ "\"") 		| otherwise = return (c, wasmodified, i:is)  	adjustlist h depth ishere underhere l = do@@ -328,7 +328,7 @@ 	 	-- For a graftloc of "foo/bar/baz", this generates 	-- ["foo", "foo/bar", "foo/bar/baz"]-	graftdirs = map (asTopFilePath . toInternalGitPath) $+	graftdirs = map (asTopFilePath . toInternalGitPath . encodeBS) $ 		mkpaths [] $ splitDirectories $ gitPath graftloc 	mkpaths _ [] = [] 	mkpaths base (d:rest) = (joinPath base </> d) : mkpaths (base ++ [d]) rest@@ -355,7 +355,7 @@ 			Just CommitObject -> 				let c = TreeCommit (LsTree.file i) (LsTree.mode i) (LsTree.sha i) 				in go (c:t) intree is-			_ -> parseerr ("unexpected object type \"" ++ LsTree.typeobj i ++ "\"")+			_ -> parseerr ("unexpected object type \"" ++ decodeBS (LsTree.typeobj i) ++ "\"") 		| otherwise = Right (t, i:is) 	parseerr = Left @@ -366,7 +366,7 @@ 	gitPath = id  instance GitPath TopFilePath where-	gitPath = getTopFilePath+	gitPath = fromRawFilePath . getTopFilePath  instance GitPath TreeItem where 	gitPath (TreeItem f _ _) = gitPath f
Git/Types.hs view
@@ -1,16 +1,23 @@ {- git data types  -- - 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.  -} +{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+ module Git.Types where  import Network.URI+import Data.String+import Data.Default import qualified Data.Map as M+import qualified Data.ByteString as S import System.Posix.Types import Utility.SafeCommand+import Utility.FileSystemEncoding  {- Support repositories on local disk, and repositories accessed via an URL.  -@@ -23,17 +30,17 @@  - else known about it.  -} data RepoLocation-	= Local { gitdir :: FilePath, worktree :: Maybe FilePath }-	| LocalUnknown FilePath+	= Local { gitdir :: RawFilePath, worktree :: Maybe RawFilePath }+	| LocalUnknown RawFilePath 	| Url URI 	| Unknown 	deriving (Show, Eq, Ord)  data Repo = Repo 	{ location :: RepoLocation-	, config :: M.Map String String+	, config :: M.Map ConfigKey ConfigValue 	-- a given git config key can actually have multiple values-	, fullconfig :: M.Map String [String]+	, fullconfig :: M.Map ConfigKey [ConfigValue] 	-- remoteName holds the name used for this repo in some other 	-- repo's list of remotes, when this repo is such a remote 	, remoteName :: Maybe RemoteName@@ -44,6 +51,33 @@ 	, gitGlobalOpts :: [CommandParam] 	} deriving (Show, Eq, Ord) +newtype ConfigKey = ConfigKey S.ByteString+	deriving (Ord, Eq)++newtype ConfigValue = ConfigValue S.ByteString+	deriving (Ord, Eq, Semigroup, Monoid)++instance Default ConfigValue where+	def = ConfigValue mempty++fromConfigKey :: ConfigKey -> String+fromConfigKey (ConfigKey s) = decodeBS' s++instance Show ConfigKey where+	show = fromConfigKey++fromConfigValue :: ConfigValue -> String+fromConfigValue (ConfigValue s) = decodeBS' s++instance Show ConfigValue where+	show = fromConfigValue++instance IsString ConfigKey where+	fromString = ConfigKey . encodeBS'++instance IsString ConfigValue where+	fromString = ConfigValue . encodeBS'+ type RemoteName = String  {- A git ref. Can be a sha1, or a branch or tag name. -}@@ -64,32 +98,31 @@  {- Types of objects that can be stored in git. -} data ObjectType = BlobObject | CommitObject | TreeObject-	deriving (Eq) -instance Show ObjectType where-	show BlobObject = "blob"-	show CommitObject = "commit"-	show TreeObject = "tree"--readObjectType :: String -> Maybe ObjectType+readObjectType :: S.ByteString -> Maybe ObjectType readObjectType "blob" = Just BlobObject readObjectType "commit" = Just CommitObject readObjectType "tree" = Just TreeObject readObjectType _ = Nothing +fmtObjectType :: ObjectType -> S.ByteString+fmtObjectType BlobObject = "blob"+fmtObjectType CommitObject = "commit"+fmtObjectType TreeObject = "tree"+ {- Types of items in a tree. -} data TreeItemType = TreeFile | TreeExecutable | TreeSymlink | TreeSubmodule-	deriving (Eq)+	deriving (Eq, Show)  {- Git uses magic numbers to denote the type of a tree item. -}-readTreeItemType :: String -> Maybe TreeItemType+readTreeItemType :: S.ByteString -> Maybe TreeItemType readTreeItemType "100644" = Just TreeFile readTreeItemType "100755" = Just TreeExecutable readTreeItemType "120000" = Just TreeSymlink readTreeItemType "160000" = Just TreeSubmodule readTreeItemType _ = Nothing -fmtTreeItemType :: TreeItemType -> String+fmtTreeItemType :: TreeItemType -> S.ByteString fmtTreeItemType TreeFile = "100644" fmtTreeItemType TreeExecutable = "100755" fmtTreeItemType TreeSymlink = "120000"
Git/UnionMerge.hs view
@@ -10,6 +10,7 @@ 	mergeIndex ) where +import qualified Data.ByteString.Lazy as L import qualified Data.ByteString.Lazy.Char8 as L8 import qualified Data.Set as S @@ -30,7 +31,7 @@  -} merge :: Ref -> Ref -> Repo -> IO () merge x y repo = do-	hashhandle <- hashObjectStart repo+	hashhandle <- hashObjectStart True repo 	ch <- catFileStart repo 	streamUpdateIndex repo 		[ lsTree x repo@@ -73,14 +74,14 @@ 	void $ cleanup   where 	go [] = noop-	go (info:file:rest) = mergeFile info file hashhandle ch >>=+	go (info:file:rest) = mergeFile (decodeBL' info) (L.toStrict file) hashhandle ch >>= 		maybe (go rest) (\l -> streamer l >> go rest) 	go (_:[]) = error $ "parse error " ++ show differ  {- Given an info line from a git raw diff, and the filename, generates  - a line suitable for update-index that union merges the two sides of the  - diff. -}-mergeFile :: String -> FilePath -> HashObjectHandle -> CatFileHandle -> IO (Maybe String)+mergeFile :: String -> RawFilePath -> HashObjectHandle -> CatFileHandle -> IO (Maybe L.ByteString) mergeFile info file hashhandle h = case filter (/= nullSha) [Ref asha, Ref bsha] of 	[] -> return Nothing 	(sha:[]) -> use sha
Git/UpdateIndex.hs view
@@ -1,11 +1,11 @@ {- git-update-index library  -- - Copyright 2011-2018 Joey Hess <id@joeyh.name>+ - Copyright 2011-2019 Joey Hess <id@joeyh.name>  -  - Licensed under the GNU AGPL version 3 or higher.  -} -{-# LANGUAGE BangPatterns, CPP #-}+{-# LANGUAGE BangPatterns, OverloadedStrings, CPP #-}  module Git.UpdateIndex ( 	Streamer,@@ -32,12 +32,14 @@ import Git.Sha import qualified Git.DiffTreeItem as Diff +import qualified Data.ByteString.Lazy as L+ {- Streamers are passed a callback and should feed it lines in the form  - read by update-index, and generated by ls-tree. -}-type Streamer = (String -> IO ()) -> IO ()+type Streamer = (L.ByteString -> IO ()) -> IO ()  {- A streamer with a precalculated value. -}-pureStreamer :: String -> Streamer+pureStreamer :: L.ByteString -> Streamer pureStreamer !s = \streamer -> streamer s  {- Streams content into update-index from a list of Streamers. -}@@ -49,8 +51,8 @@  streamUpdateIndex' :: UpdateIndexHandle -> Streamer -> IO () streamUpdateIndex' (UpdateIndexHandle _ h) a = a $ \s -> do-	hPutStr h s-	hPutStr h "\0"+	L.hPutStr h s+	L.hPutStr h "\0"  startUpdateIndex :: Repo -> IO UpdateIndexHandle startUpdateIndex repo = do@@ -84,28 +86,31 @@  {- Generates a line suitable to be fed into update-index, to add  - a given file with a given sha. -}-updateIndexLine :: Sha -> TreeItemType -> TopFilePath -> String-updateIndexLine sha treeitemtype file = concat-	[ fmtTreeItemType treeitemtype-	, " blob "-	, fromRef sha-	, "\t"-	, indexPath file-	]+updateIndexLine :: Sha -> TreeItemType -> TopFilePath -> L.ByteString+updateIndexLine sha treeitemtype file = L.fromStrict $+	fmtTreeItemType treeitemtype+	<> " blob "+	<> encodeBS (fromRef sha)+	<> "\t"+	<> indexPath file  stageFile :: Sha -> TreeItemType -> FilePath -> Repo -> IO Streamer stageFile sha treeitemtype file repo = do-	p <- toTopFilePath file repo+	p <- toTopFilePath (toRawFilePath file) repo 	return $ pureStreamer $ updateIndexLine sha treeitemtype p  {- A streamer that removes a file from the index. -} unstageFile :: FilePath -> Repo -> IO Streamer unstageFile file repo = do-	p <- toTopFilePath file repo+	p <- toTopFilePath (toRawFilePath file) repo 	return $ unstageFile' p  unstageFile' :: TopFilePath -> Streamer-unstageFile' p = pureStreamer $ "0 " ++ fromRef nullSha ++ "\t" ++ indexPath p+unstageFile' p = pureStreamer $ L.fromStrict $+	"0 "+	<> encodeBS' (fromRef nullSha)+	<> "\t"+	<> indexPath p  {- A streamer that adds a symlink to the index. -} stageSymlink :: FilePath -> Sha -> Repo -> IO Streamer@@ -113,7 +118,7 @@ 	!line <- updateIndexLine 		<$> pure sha 		<*> pure TreeSymlink-		<*> toTopFilePath file repo+		<*> toTopFilePath (toRawFilePath file) repo 	return $ pureStreamer line  {- A streamer that applies a DiffTreeItem to the index. -}
Key.hs view
@@ -78,6 +78,13 @@ 		<*> ((abs <$>) <$> arbitrary) -- chunksize cannot be negative 		<*> ((succ . abs <$>) <$> arbitrary) -- chunknum cannot be 0 or negative +-- AssociatedFile cannot be empty, and cannot contain a NUL+-- (but can be Nothing)+instance Arbitrary AssociatedFile where+	arbitrary = (AssociatedFile . fmap toRawFilePath <$> arbitrary)+		`suchThat` (/= AssociatedFile (Just S.empty))+		`suchThat` (\(AssociatedFile f) -> maybe True (S.notElem 0) f)+ instance Arbitrary Key where 	arbitrary = mkKey . const <$> arbitrary 
Limit.hs view
@@ -33,6 +33,7 @@ import Utility.Glob import Utility.HumanTime import Utility.DataUnits+import qualified Utility.RawFilePath as R  import Data.Time.Clock.POSIX import qualified Data.Set as S@@ -94,10 +95,10 @@ matchGlobFile glob = go   where 	cglob = compileGlob glob CaseSensative -- memoized-	go (MatchingFile fi) = pure $ matchGlob cglob (matchFile fi)+	go (MatchingFile fi) = pure $ matchGlob cglob (fromRawFilePath (matchFile fi)) 	go (MatchingInfo p) = matchGlob cglob <$> getInfo (providedFilePath p) 	go (MatchingKey _ (AssociatedFile Nothing)) = pure False-	go (MatchingKey _ (AssociatedFile (Just af))) = pure $ matchGlob cglob af+	go (MatchingKey _ (AssociatedFile (Just af))) = pure $ matchGlob cglob (fromRawFilePath af)  addMimeType :: String -> Annex () addMimeType = addMagicLimit "mimetype" getMagicMimeType providedMimeType@@ -110,14 +111,15 @@ 	magic <- liftIO initMagicMime 	addLimit $ matchMagic limitname querymagic' selectprovidedinfo magic glob   where-	querymagic' magic f = liftIO (isPointerFile f) >>= \case+	querymagic' magic f = liftIO (isPointerFile (toRawFilePath f)) >>= \case 		-- Avoid getting magic of a pointer file, which would 		-- wrongly be detected as text. 		Just _ -> return Nothing 		-- When the file is an annex symlink, get magic of the 		-- object file.-		Nothing -> isAnnexLink f >>= \case-			Just k -> withObjectLoc k $ querymagic magic+		Nothing -> isAnnexLink (toRawFilePath f) >>= \case+			Just k -> withObjectLoc k $+				querymagic magic . fromRawFilePath 			Nothing -> querymagic magic f  matchMagic :: String -> (Magic -> FilePath -> Annex (Maybe String)) -> (ProvidedInfo -> OptInfo String) -> Maybe Magic -> MkLimit Annex@@ -127,7 +129,7 @@ 	go (MatchingKey _ _) = pure False 	go (MatchingFile fi) = catchBoolIO $ 		maybe False (matchGlob cglob)-			<$> querymagic magic (currFile fi)+			<$> querymagic magic (fromRawFilePath (currFile fi)) 	go (MatchingInfo p) = 		matchGlob cglob <$> getInfo (selectprovidedinfo p) matchMagic limitname _ _ Nothing _ = @@ -146,7 +148,7 @@ 	islocked <- isPointerFile (currFile fi) >>= \case 		Just _key -> return False 		Nothing -> isSymbolicLink-			<$> getSymbolicLinkStatus (currFile fi)+			<$> getSymbolicLinkStatus (fromRawFilePath (currFile fi)) 	return (islocked == wantlocked)  {- Adds a limit to skip files not believed to be present@@ -190,9 +192,9 @@ limitInDir :: FilePath -> MatchFiles Annex limitInDir dir = const go   where-	go (MatchingFile fi) = checkf $ matchFile fi+	go (MatchingFile fi) = checkf $ fromRawFilePath $ matchFile fi 	go (MatchingKey _ (AssociatedFile Nothing)) = return False-	go (MatchingKey _ (AssociatedFile (Just af))) = checkf af+	go (MatchingKey _ (AssociatedFile (Just af))) = checkf (fromRawFilePath af) 	go (MatchingInfo p) = checkf =<< getInfo (providedFilePath p) 	checkf = return . elem dir . splitPath . takeDirectory @@ -239,7 +241,8 @@ 		NumCopies numcopies <- if approx 			then approxNumCopies 			else case mi of-				MatchingFile fi -> getGlobalFileNumCopies $ matchFile fi+				MatchingFile fi -> getGlobalFileNumCopies $+					fromRawFilePath $ matchFile fi 				MatchingKey _ _ -> approxNumCopies 				MatchingInfo {} -> approxNumCopies 		us <- filter (`S.notMember` notpresent)@@ -321,7 +324,8 @@ 			Just key -> checkkey sz key 			Nothing -> return False 		LimitDiskFiles -> do-			filesize <- liftIO $ catchMaybeIO $ getFileSize (currFile fi)+			filesize <- liftIO $ catchMaybeIO $+				getFileSize (fromRawFilePath (currFile fi)) 			return $ filesize `vs` Just sz 	go sz _ (MatchingKey key _) = checkkey sz key 	go sz _ (MatchingInfo p) =@@ -361,7 +365,7 @@   where 	check now k = inAnnexCheck k $ \f -> 		liftIO $ catchDefaultIO False $ do-			s <- getFileStatus f+			s <- R.getFileStatus f 			let accessed = realToFrac (accessTime s) 			let delta = now - accessed 			return $ delta <= secs
Logs.hs view
@@ -5,11 +5,16 @@  - Licensed under the GNU AGPL version 3 or higher.  -} +{-# LANGUAGE OverloadedStrings #-}+ module Logs where  import Annex.Common import Annex.DirHashes +import qualified Data.ByteString as S+import qualified System.FilePath.ByteString as P+ {- There are several varieties of log file formats. -} data LogVariety 	= OldUUIDBasedLog@@ -22,7 +27,7 @@  {- Converts a path from the git-annex branch into one of the varieties  - of logs used by git-annex, if it's a known path. -}-getLogVariety :: FilePath -> Maybe LogVariety+getLogVariety :: RawFilePath -> Maybe LogVariety getLogVariety f 	| f `elem` topLevelOldUUIDBasedLogs = Just OldUUIDBasedLog 	| f `elem` topLevelNewUUIDBasedLogs = Just NewUUIDBasedLog@@ -34,7 +39,7 @@ 	| otherwise = PresenceLog <$> firstJust (presenceLogs f)  {- All the old-format uuid-based logs stored in the top of the git-annex branch. -}-topLevelOldUUIDBasedLogs :: [FilePath]+topLevelOldUUIDBasedLogs :: [RawFilePath] topLevelOldUUIDBasedLogs = 	[ uuidLog 	, remoteLog@@ -49,161 +54,172 @@ 	]  {- All the new-format uuid-based logs stored in the top of the git-annex branch. -}-topLevelNewUUIDBasedLogs :: [FilePath]+topLevelNewUUIDBasedLogs :: [RawFilePath] topLevelNewUUIDBasedLogs = 	[ exportLog 	]   {- All the ways to get a key from a presence log file -}-presenceLogs :: FilePath -> [Maybe Key]+presenceLogs :: RawFilePath -> [Maybe Key] presenceLogs f = 	[ urlLogFileKey f 	, locationLogFileKey f 	]  {- Top-level logs that are neither UUID based nor presence logs. -}-otherLogs :: [FilePath]+otherLogs :: [RawFilePath] otherLogs = 	[ numcopiesLog 	, groupPreferredContentLog 	] -uuidLog :: FilePath+uuidLog :: RawFilePath uuidLog = "uuid.log" -numcopiesLog :: FilePath+numcopiesLog :: RawFilePath numcopiesLog = "numcopies.log" -configLog :: FilePath+configLog :: RawFilePath configLog = "config.log" -remoteLog :: FilePath+remoteLog :: RawFilePath remoteLog = "remote.log" -trustLog :: FilePath+trustLog :: RawFilePath trustLog = "trust.log" -groupLog :: FilePath+groupLog :: RawFilePath groupLog = "group.log" -preferredContentLog :: FilePath+preferredContentLog :: RawFilePath preferredContentLog = "preferred-content.log" -requiredContentLog :: FilePath+requiredContentLog :: RawFilePath requiredContentLog = "required-content.log" -groupPreferredContentLog :: FilePath+groupPreferredContentLog :: RawFilePath groupPreferredContentLog = "group-preferred-content.log" -scheduleLog :: FilePath+scheduleLog :: RawFilePath scheduleLog = "schedule.log" -activityLog :: FilePath+activityLog :: RawFilePath activityLog = "activity.log" -differenceLog :: FilePath+differenceLog :: RawFilePath differenceLog = "difference.log" -multicastLog :: FilePath+multicastLog :: RawFilePath multicastLog = "multicast.log" -exportLog :: FilePath+exportLog :: RawFilePath exportLog = "export.log"  {- The pathname of the location log file for a given key. -}-locationLogFile :: GitConfig -> Key -> String-locationLogFile config key = branchHashDir config key </> keyFile key ++ ".log"+locationLogFile :: GitConfig -> Key -> RawFilePath+locationLogFile config key =+	branchHashDir config key P.</> keyFile key <> ".log"  {- The filename of the url log for a given key. -}-urlLogFile :: GitConfig -> Key -> FilePath-urlLogFile config key = branchHashDir config key </> keyFile key ++ urlLogExt+urlLogFile :: GitConfig -> Key -> RawFilePath+urlLogFile config key = +	branchHashDir config key P.</> keyFile key <> urlLogExt  {- Old versions stored the urls elsewhere. -}-oldurlLogs :: GitConfig -> Key -> [FilePath]+oldurlLogs :: GitConfig -> Key -> [RawFilePath] oldurlLogs config key =-	[ "remote/web" </> hdir </> serializeKey key ++ ".log"-	, "remote/web" </> hdir </> keyFile key ++ ".log"+	[ "remote/web" P.</> hdir P.</> serializeKey' key <> ".log"+	, "remote/web" P.</> hdir P.</> keyFile key <> ".log" 	]   where 	hdir = branchHashDir config key -urlLogExt :: String+urlLogExt :: S.ByteString urlLogExt = ".log.web"  {- Does not work on oldurllogs. -}-isUrlLog :: FilePath -> Bool-isUrlLog file = urlLogExt `isSuffixOf` file+isUrlLog :: RawFilePath -> Bool+isUrlLog file = urlLogExt `S.isSuffixOf` file  {- The filename of the remote state log for a given key. -}-remoteStateLogFile :: GitConfig -> Key -> FilePath-remoteStateLogFile config key = branchHashDir config key -	</> keyFile key ++ remoteStateLogExt+remoteStateLogFile :: GitConfig -> Key -> RawFilePath+remoteStateLogFile config key = +	(branchHashDir config key P.</> keyFile key)+		<> remoteStateLogExt -remoteStateLogExt :: String+remoteStateLogExt :: S.ByteString remoteStateLogExt = ".log.rmt" -isRemoteStateLog :: FilePath -> Bool-isRemoteStateLog path = remoteStateLogExt `isSuffixOf` path+isRemoteStateLog :: RawFilePath -> Bool+isRemoteStateLog path = remoteStateLogExt `S.isSuffixOf` path  {- The filename of the chunk log for a given key. -}-chunkLogFile :: GitConfig -> Key -> FilePath-chunkLogFile config key = branchHashDir config key </> keyFile key ++ chunkLogExt+chunkLogFile :: GitConfig -> Key -> RawFilePath+chunkLogFile config key = +	(branchHashDir config key P.</> keyFile key)+		<> chunkLogExt -chunkLogExt :: String+chunkLogExt :: S.ByteString chunkLogExt = ".log.cnk" -isChunkLog :: FilePath -> Bool-isChunkLog path = chunkLogExt `isSuffixOf` path+isChunkLog :: RawFilePath -> Bool+isChunkLog path = chunkLogExt `S.isSuffixOf` path  {- The filename of the metadata log for a given key. -}-metaDataLogFile :: GitConfig -> Key -> FilePath-metaDataLogFile config key = branchHashDir config key </> keyFile key ++ metaDataLogExt+metaDataLogFile :: GitConfig -> Key -> RawFilePath+metaDataLogFile config key =+	(branchHashDir config key P.</> keyFile key)+		<> metaDataLogExt -metaDataLogExt :: String+metaDataLogExt :: S.ByteString metaDataLogExt = ".log.met" -isMetaDataLog :: FilePath -> Bool-isMetaDataLog path = metaDataLogExt `isSuffixOf` path+isMetaDataLog :: RawFilePath -> Bool+isMetaDataLog path = metaDataLogExt `S.isSuffixOf` path  {- The filename of the remote metadata log for a given key. -}-remoteMetaDataLogFile :: GitConfig -> Key -> FilePath-remoteMetaDataLogFile config key = branchHashDir config key </> keyFile key ++ remoteMetaDataLogExt+remoteMetaDataLogFile :: GitConfig -> Key -> RawFilePath+remoteMetaDataLogFile config key = +	(branchHashDir config key P.</> keyFile key)+		<> remoteMetaDataLogExt -remoteMetaDataLogExt :: String+remoteMetaDataLogExt :: S.ByteString remoteMetaDataLogExt = ".log.rmet" -isRemoteMetaDataLog :: FilePath -> Bool-isRemoteMetaDataLog path = remoteMetaDataLogExt `isSuffixOf` path+isRemoteMetaDataLog :: RawFilePath -> Bool+isRemoteMetaDataLog path = remoteMetaDataLogExt `S.isSuffixOf` path  {- The filename of the remote content identifier log for a given key. -}-remoteContentIdentifierLogFile :: GitConfig -> Key -> FilePath-remoteContentIdentifierLogFile config key = branchHashDir config key </> keyFile key ++ remoteContentIdentifierExt+remoteContentIdentifierLogFile :: GitConfig -> Key -> RawFilePath+remoteContentIdentifierLogFile config key =+	(branchHashDir config key P.</> keyFile key)+		<> remoteContentIdentifierExt -remoteContentIdentifierExt :: String+remoteContentIdentifierExt :: S.ByteString remoteContentIdentifierExt = ".log.cid" -isRemoteContentIdentifierLog :: FilePath -> Bool-isRemoteContentIdentifierLog path = remoteContentIdentifierExt `isSuffixOf` path+isRemoteContentIdentifierLog :: RawFilePath -> Bool+isRemoteContentIdentifierLog path = remoteContentIdentifierExt `S.isSuffixOf` path  {- From an extension and a log filename, get the key that it's a log for. -}-extLogFileKey :: String -> FilePath -> Maybe Key+extLogFileKey :: S.ByteString -> RawFilePath -> Maybe Key extLogFileKey expectedext path-	| ext == expectedext = fileKey base+	| encodeBS' ext == expectedext = fileKey (toRawFilePath base) 	| otherwise = Nothing   where-	file = takeFileName path+	file = takeFileName (fromRawFilePath path) 	(base, ext) = splitAt (length file - extlen) file-	extlen = length expectedext+	extlen = S.length expectedext  {- Converts a url log file into a key.  - (Does not work on oldurlLogs.) -}-urlLogFileKey :: FilePath -> Maybe Key+urlLogFileKey :: RawFilePath -> Maybe Key urlLogFileKey = extLogFileKey urlLogExt  {- Converts a pathname into a key if it's a location log. -}-locationLogFileKey :: FilePath -> Maybe Key+locationLogFileKey :: RawFilePath -> Maybe Key locationLogFileKey path 	-- Want only xx/yy/foo.log, not .log files in other places.-	| length (splitDirectories path) /= 3 = Nothing+	| length (splitDirectories (fromRawFilePath path)) /= 3 = Nothing 	| otherwise = extLogFileKey ".log" path
Logs/Config.hs view
@@ -6,8 +6,8 @@  -}  module Logs.Config (-	ConfigName,-	ConfigValue,+	ConfigKey(..),+	ConfigValue(..), 	setGlobalConfig, 	unsetGlobalConfig, 	getGlobalConfig,@@ -18,48 +18,52 @@ import Logs import Logs.MapLog import qualified Annex.Branch+import Git.Types (ConfigKey(..), ConfigValue(..))  import qualified Data.Map as M+import qualified Data.ByteString as S import qualified Data.ByteString.Lazy as L import qualified Data.Attoparsec.ByteString.Lazy as A import Data.ByteString.Builder -type ConfigName = String-type ConfigValue = String--setGlobalConfig :: ConfigName -> ConfigValue -> Annex ()+setGlobalConfig :: ConfigKey -> ConfigValue -> Annex () setGlobalConfig name new = do 	curr <- getGlobalConfig name 	when (curr /= Just new) $ 		setGlobalConfig' name new -setGlobalConfig' :: ConfigName -> ConfigValue -> Annex ()+setGlobalConfig' :: ConfigKey -> ConfigValue -> Annex () setGlobalConfig' name new = do 	c <- liftIO currentVectorClock 	Annex.Branch.change configLog $  		buildGlobalConfig . changeMapLog c name new . parseGlobalConfig -unsetGlobalConfig :: ConfigName -> Annex ()+unsetGlobalConfig :: ConfigKey -> Annex () unsetGlobalConfig name = do 	curr <- getGlobalConfig name 	when (curr /= Nothing) $-		setGlobalConfig' name "" -- set to empty string to unset+		-- set to empty string to unset+		setGlobalConfig' name (ConfigValue mempty)  -- Reads the global config log every time.-getGlobalConfig :: ConfigName -> Annex (Maybe ConfigValue)+-- It's more efficient to use Config.GitConfig.+getGlobalConfig :: ConfigKey -> Annex (Maybe ConfigValue) getGlobalConfig name = M.lookup name <$> loadGlobalConfig -buildGlobalConfig :: MapLog ConfigName ConfigValue -> Builder-buildGlobalConfig = buildMapLog fieldbuilder valuebuilder+buildGlobalConfig :: MapLog ConfigKey ConfigValue -> Builder+buildGlobalConfig = buildMapLog configkeybuilder valuebuilder   where-	fieldbuilder = byteString . encodeBS-	valuebuilder = byteString . encodeBS+	configkeybuilder (ConfigKey k) = byteString k+	valuebuilder (ConfigValue v) = byteString v -parseGlobalConfig :: L.ByteString -> MapLog ConfigName ConfigValue-parseGlobalConfig = parseMapLog string string+parseGlobalConfig :: L.ByteString -> MapLog ConfigKey ConfigValue+parseGlobalConfig = parseMapLog configkeyparser valueparser   where-	string = decodeBS <$> A.takeByteString+	configkeyparser = ConfigKey <$> A.takeByteString+	valueparser = ConfigValue <$> A.takeByteString -loadGlobalConfig :: Annex (M.Map ConfigName ConfigValue)-loadGlobalConfig = M.filter (not . null) . simpleMap . parseGlobalConfig+loadGlobalConfig :: Annex (M.Map ConfigKey ConfigValue)+loadGlobalConfig = M.filter (\(ConfigValue v) -> not (S.null v)) +	. simpleMap+	. parseGlobalConfig 	<$> Annex.Branch.get configLog
Logs/Export.hs view
@@ -5,6 +5,8 @@  - Licensed under the GNU AGPL version 3 or higher.  -} +{-# LANGUAGE OverloadedStrings #-}+ module Logs.Export ( 	Exported, 	mkExported,@@ -37,6 +39,8 @@ import qualified Data.Attoparsec.ByteString.Lazy as A import qualified Data.Attoparsec.ByteString.Char8 as A8 import Data.ByteString.Builder+import Data.Either+import Data.Char  -- This constuctor is not itself exported to other modules, to enforce -- consistent use of exportedTreeishes.@@ -176,8 +180,9 @@ getExportExcluded :: UUID -> Annex [Git.Tree.TreeItem] getExportExcluded u = do 	logf <- fromRepo $ gitAnnexExportExcludeLog u-	liftIO $ catchDefaultIO [] $ -		(map parser . lines)-			<$> readFile logf+	liftIO $ catchDefaultIO [] $ parser <$> L.readFile logf   where-	parser = Git.Tree.lsTreeItemToTreeItem . Git.LsTree.parseLsTree+	parser = map Git.Tree.lsTreeItemToTreeItem+		. rights+		. map Git.LsTree.parseLsTree+		. L.split (fromIntegral $ ord '\n')
Logs/Location.hs view
@@ -71,7 +71,7 @@ loggedLocationsRef :: Ref -> Annex [UUID] loggedLocationsRef ref = map (toUUID . fromLogInfo) . getLog <$> catObject ref -getLoggedLocations :: (FilePath -> Annex [LogInfo]) -> Key -> Annex [UUID]+getLoggedLocations :: (RawFilePath -> Annex [LogInfo]) -> Key -> Annex [UUID] getLoggedLocations getter key = do 	config <- Annex.getGitConfig 	map (toUUID . fromLogInfo) <$> getter (locationLogFile config key)
Logs/MetaData.hs view
@@ -57,7 +57,7 @@ getCurrentMetaData :: Key -> Annex MetaData getCurrentMetaData = getCurrentMetaData' metaDataLogFile -getCurrentMetaData' :: (GitConfig -> Key -> FilePath) -> Key -> Annex MetaData+getCurrentMetaData' :: (GitConfig -> Key -> RawFilePath) -> Key -> Annex MetaData getCurrentMetaData' getlogfile k = do 	config <- Annex.getGitConfig 	ls <- S.toAscList <$> readLog (getlogfile config k)@@ -95,7 +95,7 @@ addMetaData :: Key -> MetaData -> Annex () addMetaData = addMetaData' metaDataLogFile -addMetaData' :: (GitConfig -> Key -> FilePath) -> Key -> MetaData -> Annex ()+addMetaData' :: (GitConfig -> Key -> RawFilePath) -> Key -> MetaData -> Annex () addMetaData' getlogfile k metadata =  	addMetaDataClocked' getlogfile k metadata =<< liftIO currentVectorClock @@ -106,7 +106,7 @@ addMetaDataClocked :: Key -> MetaData -> VectorClock -> Annex () addMetaDataClocked = addMetaDataClocked' metaDataLogFile -addMetaDataClocked' :: (GitConfig -> Key -> FilePath) -> Key -> MetaData -> VectorClock -> Annex ()+addMetaDataClocked' :: (GitConfig -> Key -> RawFilePath) -> Key -> MetaData -> VectorClock -> Annex () addMetaDataClocked' getlogfile k d@(MetaData m) c 	| d == emptyMetaData = noop 	| otherwise = do@@ -151,5 +151,5 @@ 					const $ buildLog l 				return True -readLog :: FilePath -> Annex (Log MetaData)+readLog :: RawFilePath -> Annex (Log MetaData) readLog = parseLog <$$> Annex.Branch.get
Logs/PreferredContent.hs view
@@ -42,7 +42,6 @@ import Types.Remote (RemoteConfig) import Logs.Group import Logs.Remote-import Types.FileMatcher import Types.StandardGroups import Limit 
Logs/PreferredContent/Raw.hs view
@@ -28,7 +28,7 @@ requiredContentSet :: UUID -> PreferredContentExpression -> Annex () requiredContentSet = setLog requiredContentLog -setLog :: FilePath -> UUID -> PreferredContentExpression -> Annex ()+setLog :: RawFilePath -> UUID -> PreferredContentExpression -> Annex () setLog logfile uuid@(UUID _) val = do 	c <- liftIO currentVectorClock 	Annex.Branch.change logfile $
Logs/Presence.hs view
@@ -30,7 +30,7 @@  {- Adds a LogLine to the log, removing any LogLines that are obsoleted by  - adding it. -}-addLog :: FilePath -> LogLine -> Annex ()+addLog :: RawFilePath -> LogLine -> Annex () addLog file line = Annex.Branch.change file $ \b -> 	buildLog $ compactLog (line : parseLog b) @@ -38,14 +38,14 @@  - older timestamp, that LogLine is preserved, rather than updating the log  - with a newer timestamp.  -}-maybeAddLog :: FilePath -> LogLine -> Annex ()+maybeAddLog :: RawFilePath -> LogLine -> Annex () maybeAddLog file line = Annex.Branch.maybeChange file $ \s -> do 	m <- insertNewStatus line $ logMap $ parseLog s 	return $ buildLog $ mapLog m  {- Reads a log file.  - Note that the LogLines returned may be in any order. -}-readLog :: FilePath -> Annex [LogLine]+readLog :: RawFilePath -> Annex [LogLine] readLog = parseLog <$$> Annex.Branch.get  {- Generates a new LogLine with the current time. -}@@ -55,10 +55,10 @@ 	return $ LogLine c s i  {- Reads a log and returns only the info that is still in effect. -}-currentLogInfo :: FilePath -> Annex [LogInfo]+currentLogInfo :: RawFilePath -> Annex [LogInfo] currentLogInfo file = map info <$> currentLog file -currentLog :: FilePath -> Annex [LogLine]+currentLog :: RawFilePath -> Annex [LogLine] currentLog file = filterPresent <$> readLog file  {- Reads a historical version of a log and returns the info that was in@@ -66,6 +66,6 @@  -  - The date is formatted as shown in gitrevisions man page.  -}-historicalLogInfo :: RefDate -> FilePath -> Annex [LogInfo]+historicalLogInfo :: RefDate -> RawFilePath -> Annex [LogInfo] historicalLogInfo refdate file = map info . filterPresent . parseLog 	<$> Annex.Branch.getHistorical refdate file
Logs/SingleValue.hs view
@@ -25,13 +25,13 @@  import qualified Data.Set as S -readLog :: (Ord v, SingleValueSerializable v) => FilePath -> Annex (Log v)+readLog :: (Ord v, SingleValueSerializable v) => RawFilePath -> Annex (Log v) readLog = parseLog <$$> Annex.Branch.get -getLog :: (Ord v, SingleValueSerializable v) => FilePath -> Annex (Maybe v)+getLog :: (Ord v, SingleValueSerializable v) => RawFilePath -> Annex (Maybe v) getLog = newestValue <$$> readLog -setLog :: (SingleValueSerializable v) => FilePath -> v -> Annex ()+setLog :: (SingleValueSerializable v) => RawFilePath -> v -> Annex () setLog f v = do 	c <- liftIO currentVectorClock 	let ent = LogEntry c v
Logs/Smudge.hs view
@@ -5,6 +5,8 @@  - Licensed under the GNU AGPL version 3 or higher.  -} +{-# LANGUAGE OverloadedStrings #-}+ module Logs.Smudge where  import Annex.Common@@ -15,8 +17,8 @@ smudgeLog :: Key -> TopFilePath -> Annex () smudgeLog k f = do 	logf <- fromRepo gitAnnexSmudgeLog-	appendLogFile logf gitAnnexSmudgeLock $ -		serializeKey k ++ " " ++ getTopFilePath f+	appendLogFile logf gitAnnexSmudgeLock $ fromRawFilePath $+		serializeKey' k <> " " <> getTopFilePath f  -- | Streams all smudged files, and then empties the log at the end. --@@ -37,4 +39,4 @@ 		let (ks, f) = separate (== ' ') l 		in do 			k <- deserializeKey ks-			return (k, asTopFilePath f)+			return (k, asTopFilePath (toRawFilePath f))
Logs/Transfer.hs view
@@ -31,7 +31,7 @@ describeTransfer t info = unwords 	[ show $ transferDirection t 	, show $ transferUUID t-	, actionItemDesc $ ActionItemAssociatedFile+	, decodeBS' $ actionItemDesc $ ActionItemAssociatedFile 		(associatedFile info) 		(transferKey t) 	, show $ bytesComplete info@@ -195,12 +195,12 @@ transferFile :: Transfer -> Git.Repo -> FilePath transferFile (Transfer direction u kd) r = transferDir direction r 	</> filter (/= '/') (fromUUID u)-	</> keyFile (mkKey (const kd))+	</> fromRawFilePath (keyFile (mkKey (const kd)))  {- The transfer information file to use to record a failed Transfer -} failedTransferFile :: Transfer -> Git.Repo -> FilePath failedTransferFile (Transfer direction u kd) r = failedTransferDir u direction r-	</> keyFile (mkKey (const kd))+	</> fromRawFilePath (keyFile (mkKey (const kd)))  {- The transfer lock file corresponding to a given transfer info file. -} transferLockFile :: FilePath -> FilePath@@ -215,7 +215,7 @@ 		[direction, u, key] -> Transfer 			<$> parseDirection direction 			<*> pure (toUUID u)-			<*> fmap (fromKey id) (fileKey key)+			<*> fmap (fromKey id) (fileKey (toRawFilePath key)) 		_ -> Nothing   where 	bits = splitDirectories file@@ -245,7 +245,7 @@ #endif 	-- comes last; arbitrary content 	, let AssociatedFile afile = associatedFile info-	  in fromMaybe "" afile+	  in maybe "" fromRawFilePath afile 	]  readTransferInfoFile :: Maybe PID -> FilePath -> IO (Maybe TransferInfo)@@ -263,7 +263,7 @@ 	<*> pure Nothing 	<*> pure Nothing 	<*> bytes-	<*> pure (AssociatedFile (if null filename then Nothing else Just filename))+	<*> pure (AssociatedFile (if null filename then Nothing else Just (toRawFilePath filename))) 	<*> pure False   where #ifdef mingw32_HOST_OS
Logs/Transitions.hs view
@@ -12,6 +12,8 @@  - Licensed under the GNU AGPL version 3 or higher.  -} +{-# LANGUAGE OverloadedStrings #-}+ module Logs.Transitions where  import Annex.Common@@ -26,7 +28,7 @@ import qualified Data.Attoparsec.ByteString.Lazy as A import qualified Data.Attoparsec.ByteString.Char8 as A8 -transitionsLog :: FilePath+transitionsLog :: RawFilePath transitionsLog = "transitions.log"  data Transition@@ -94,6 +96,6 @@  {- Typically ran with Annex.Branch.change, but we can't import Annex.Branch  - here since it depends on this module. -}-recordTransitions :: (FilePath -> (L.ByteString -> Builder) -> Annex ()) -> Transitions -> Annex ()+recordTransitions :: (RawFilePath -> (L.ByteString -> Builder) -> Annex ()) -> Transitions -> Annex () recordTransitions changer t = changer transitionsLog $ 	buildTransitions . S.union t . parseTransitionsStrictly "local"
Messages.hs view
@@ -5,6 +5,8 @@  - Licensed under the GNU AGPL version 3 or higher.  -} +{-# LANGUAGE OverloadedStrings #-}+ module Messages ( 	showStart, 	showStart',@@ -53,6 +55,7 @@ import System.Log.Handler (setFormatter) import System.Log.Handler.Simple import Control.Concurrent+import qualified Data.ByteString as S  import Common import Types@@ -66,21 +69,21 @@ import qualified Messages.JSON as JSON import qualified Annex -showStart :: String -> FilePath -> Annex ()+showStart :: String -> RawFilePath -> Annex () showStart command file = outputMessage json $-	command ++ " " ++ file ++ " "+	encodeBS' command <> " " <> file <> " "   where 	json = JSON.start command (Just file) Nothing  showStart' :: String -> Maybe String -> Annex ()-showStart' command mdesc = outputMessage json $+showStart' command mdesc = outputMessage json $ encodeBS' $ 	command ++ (maybe "" (" " ++) mdesc) ++ " "   where 	json = JSON.start command Nothing Nothing  showStartKey :: String -> Key -> ActionItem -> Annex () showStartKey command key i = outputMessage json $-	command ++ " " ++ actionItemDesc i ++ " "+	encodeBS' command <> " " <> actionItemDesc i <> " "   where 	json = JSON.start command (actionItemWorkTreeFile i) (Just key) @@ -112,7 +115,7 @@ showEndMessage (CustomOutput _) = const noop  showNote :: String -> Annex ()-showNote s = outputMessage (JSON.note s) $ "(" ++ s ++ ") "+showNote s = outputMessage (JSON.note s) $ encodeBS' $ "(" ++ s ++ ") "  showAction :: String -> Annex () showAction s = showNote $ s ++ "..."@@ -127,7 +130,7 @@ 			Annex.changeState $ \s -> s { Annex.output = st' } 		| sideActionBlock st == InBlock = return () 		| otherwise = p-	p = outputMessage JSON.none $ "(" ++ m ++ "...)\n"+	p = outputMessage JSON.none $ encodeBS' $ "(" ++ m ++ "...)\n" 			 showStoringStateAction :: Annex () showStoringStateAction = showSideAction "recording state in git"@@ -171,7 +174,7 @@ 	outputMessage JSON.none "\n"  showLongNote :: String -> Annex ()-showLongNote s = outputMessage (JSON.note s) (formatLongNote s)+showLongNote s = outputMessage (JSON.note s) (encodeBS' (formatLongNote s))  formatLongNote :: String -> String formatLongNote s = '\n' : indent s ++ "\n"@@ -179,7 +182,8 @@ -- Used by external special remote, displayed same as showLongNote -- to console, but json object containing the info is emitted immediately. showInfo :: String -> Annex ()-showInfo s = outputMessage' outputJSON (JSON.info s) (formatLongNote s)+showInfo s = outputMessage' outputJSON (JSON.info s) $+	encodeBS' (formatLongNote s)  showEndOk :: Annex () showEndOk = showEndResult True@@ -188,9 +192,9 @@ showEndFail = showEndResult False  showEndResult :: Bool -> Annex ()-showEndResult ok = outputMessage (JSON.end ok) $ endResult ok ++ "\n"+showEndResult ok = outputMessage (JSON.end ok) $ endResult ok <> "\n" -endResult :: Bool -> String+endResult :: Bool -> S.ByteString endResult True = "ok" endResult False = "failed" @@ -238,11 +242,11 @@ 	r <- a 	outputMessage (JSON.end r) "" -showHeader :: String -> Annex ()-showHeader h = outputMessage JSON.none $ (h ++ ": ")+showHeader :: S.ByteString -> Annex ()+showHeader h = outputMessage JSON.none (h <> ": ") -showRaw :: String -> Annex ()-showRaw s = outputMessage JSON.none (s ++ "\n")+showRaw :: S.ByteString -> Annex ()+showRaw s = outputMessage JSON.none (s <> "\n")  setupConsole :: IO () setupConsole = do
Messages/Internal.hs view
@@ -14,17 +14,19 @@ import qualified Messages.JSON as JSON import Messages.JSON (JSONBuilder) +import qualified Data.ByteString as S+ withMessageState :: (MessageState -> Annex a) -> Annex a withMessageState a = Annex.getState Annex.output >>= a -outputMessage :: JSONBuilder -> String -> Annex ()+outputMessage :: JSONBuilder -> S.ByteString -> Annex () outputMessage = outputMessage' bufferJSON -outputMessage' :: (JSONBuilder -> MessageState -> Annex Bool) -> JSONBuilder -> String -> Annex ()+outputMessage' :: (JSONBuilder -> MessageState -> Annex Bool) -> JSONBuilder -> S.ByteString -> Annex () outputMessage' jsonoutputter jsonbuilder msg = withMessageState $ \s -> case outputType s of 	NormalOutput-		| concurrentOutputEnabled s -> concurrentMessage s False msg q-		| otherwise -> liftIO $ flushed $ putStr msg+		| concurrentOutputEnabled s -> concurrentMessage s False (decodeBS msg) q+		| otherwise -> liftIO $ flushed $ S.putStr msg 	JSONOutput _ -> void $ jsonoutputter jsonbuilder s 	QuietOutput -> q 
Messages/JSON.hs view
@@ -43,6 +43,7 @@ import Utility.Metered import Utility.Percentage import Utility.Aeson+import Utility.FileSystemEncoding  -- A global lock to avoid concurrent threads emitting json at the same time. {-# NOINLINE emitLock #-}@@ -63,13 +64,13 @@ none :: JSONBuilder none = id -start :: String -> Maybe FilePath -> Maybe Key -> JSONBuilder+start :: String -> Maybe RawFilePath -> Maybe Key -> JSONBuilder start command file key _ = Just (o, False)   where 	Object o = toJSON' $ JSONActionItem 		{ itemCommand = Just command 		, itemKey = key-		, itemFile = file+		, itemFile = fromRawFilePath <$> file 		, itemAdded = Nothing 		} 
Messages/Progress.hs view
@@ -6,6 +6,7 @@  -}  {-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE OverloadedStrings #-}  module Messages.Progress where 
P2P/Annex.hs view
@@ -47,7 +47,7 @@ 		size <- liftIO $ catchDefaultIO 0 $ getFileSize f 		runner (next (Len size)) 	ContentSize k next -> do-		let getsize = liftIO . catchMaybeIO . getFileSize+		let getsize = liftIO . catchMaybeIO . getFileSize . fromRawFilePath 		size <- inAnnex' isJust Nothing getsize k 		runner (next (Len <$> size)) 	ReadContent k af o sender next -> do
P2P/IO.hs view
@@ -293,7 +293,7 @@ 	 	serviceproc = gitCreateProcess 		[ Param cmd-		, File (repoPath (connRepo conn))+		, File (fromRawFilePath (repoPath (connRepo conn))) 		] (connRepo conn)  	setup = do
P2P/Protocol.hs view
@@ -22,6 +22,7 @@ import Utility.Applicative import Utility.PartialPrelude import Utility.Metered+import Utility.FileSystemEncoding import Git.FilePath import Annex.ChangedRefs (ChangedRefs) @@ -166,17 +167,17 @@ instance Proto.Serializable AssociatedFile where 	serialize (AssociatedFile Nothing) = "" 	serialize (AssociatedFile (Just af)) = -		toInternalGitPath $ concatMap esc af+		decodeBS' $ toInternalGitPath $ encodeBS' $ concatMap esc $ fromRawFilePath af 	  where 		esc '%' = "%%" 		esc c  			| isSpace c = "%" 			| otherwise = [c] 	-	deserialize s = case fromInternalGitPath $ deesc [] s of+	deserialize s = case fromRawFilePath $ fromInternalGitPath $ toRawFilePath $ deesc [] s of 		[] -> Just (AssociatedFile Nothing) 		f-			| isRelative f -> Just (AssociatedFile (Just f))+			| isRelative f -> Just $ AssociatedFile $ Just $ toRawFilePath f 			| otherwise -> Nothing 	  where 	  	deesc b [] = reverse b
Remote.hs view
@@ -74,7 +74,7 @@ import Remote.List import Config import Config.DynamicConfig-import Git.Types (RemoteName)+import Git.Types (RemoteName, ConfigKey(..), fromConfigValue) import Utility.Aeson  {- Map from UUIDs of Remotes to a calculated value. -}@@ -147,10 +147,12 @@  {- Finds the remote or remote group matching the name. -} byNameOrGroup :: RemoteName -> Annex [Remote]-byNameOrGroup n = go =<< getConfigMaybe (ConfigKey ("remotes." ++ n))+byNameOrGroup n = go =<< getConfigMaybe (ConfigKey ("remotes." <> encodeBS' n))   where-	go (Just l) = catMaybes <$> mapM (byName . Just) (splitc ' ' l)-	go Nothing = maybeToList <$> byName (Just n)+	go (Just l) = catMaybes+		<$> mapM (byName . Just) (splitc ' ' (fromConfigValue l))+	go Nothing = maybeToList+		<$> byName (Just n)  {- Only matches remote name, not UUID -} byNameOnly :: RemoteName -> Annex (Maybe Remote)
Remote/Adb.hs view
@@ -212,7 +212,7 @@ androidHashDir adir k = AndroidPath $  	fromAndroidPath adir ++ "/" ++ hdir   where-	hdir = replace [pathSeparator] "/" (hashDirLower def k)+	hdir = replace [pathSeparator] "/" (fromRawFilePath (hashDirLower def k))  storeExportM :: AndroidSerial -> AndroidPath -> FilePath -> Key -> ExportLocation -> MeterUpdate -> Annex Bool  storeExportM serial adir src _k loc _p = store' serial dest src@@ -269,7 +269,7 @@ 		let (stat, fn) = separate (== '\t') l 		    sz = fromMaybe 0 (readish (takeWhile (/= ' ') stat)) 		    cid = ContentIdentifier (encodeBS' stat)-		    loc = mkImportLocation $ +		    loc = mkImportLocation $ toRawFilePath $  		    	Posix.makeRelative (fromAndroidPath adir) fn 		in Just (loc, (cid, sz)) 	mk _ = Nothing@@ -331,7 +331,7 @@  androidExportLocation :: AndroidPath -> ExportLocation -> AndroidPath androidExportLocation adir loc = AndroidPath $-	fromAndroidPath adir ++ "/" ++ fromExportLocation loc+	fromAndroidPath adir ++ "/" ++ fromRawFilePath (fromExportLocation loc)  -- | List all connected Android devices. enumerateAdbConnected :: IO [AndroidSerial]
Remote/BitTorrent.hs view
@@ -195,7 +195,7 @@ 			createAnnexDirectory (parentDir torrent) 			if isTorrentMagnetUrl u 				then withOtherTmp $ \othertmp -> do-					kf <- keyFile <$> torrentUrlKey u+					kf <- fromRawFilePath . keyFile <$> torrentUrlKey u 					let metadir = othertmp </> "torrentmeta" </> kf 					createAnnexDirectory metadir 					showOutput@@ -239,7 +239,7 @@ downloadTorrentContent k u dest filenum p = do 	torrent <- tmpTorrentFile u 	withOtherTmp $ \othertmp -> do-		kf <- keyFile <$> torrentUrlKey u+		kf <- fromRawFilePath . keyFile <$> torrentUrlKey u 		let downloaddir = othertmp </> "torrent" </> kf 		createAnnexDirectory downloaddir 		f <- wantedfile torrent
Remote/Bup.hs view
@@ -1,6 +1,6 @@ {- Using bup as a remote.  -- - Copyright 2011-2014 Joey Hess <id@joeyh.name>+ - Copyright 2011-2019 Joey Hess <id@joeyh.name>  -  - Licensed under the GNU AGPL version 3 or higher.  -}@@ -8,6 +8,7 @@ module Remote.Bup (remote) where  import qualified Data.Map as M+import qualified Data.ByteString as S import qualified Data.ByteString.Lazy as L import Data.ByteString.Lazy.UTF8 (fromString) @@ -15,6 +16,7 @@ import qualified Annex import Types.Remote import Types.Creds+import Git.Types (ConfigValue(..), fromConfigKey) import qualified Git import qualified Git.Command import qualified Git.Config@@ -207,12 +209,12 @@ 		then do 			showAction "storing uuid" 			unlessM (onBupRemote r boolSystem "git"-				[Param "config", Param "annex.uuid", Param v]) $+				[Param "config", Param (fromConfigKey configkeyUUID), Param v]) $ 					giveup "ssh failed" 		else liftIO $ do 			r' <- Git.Config.read r-			let olduuid = Git.Config.get "annex.uuid" "" r'-			when (olduuid == "") $+			let ConfigValue olduuid = Git.Config.get configkeyUUID mempty r'+			when (S.null olduuid) $ 				Git.Command.run 					[ Param "config" 					, Param "annex.uuid"@@ -228,7 +230,7 @@ 	(sshcmd, sshparams) <- Ssh.toRepo NoConsumeStdin r c remotecmd 	liftIO $ runner sshcmd sshparams   where-	path = Git.repoPath r+	path = fromRawFilePath $ Git.repoPath r 	base = fromMaybe path (stripPrefix "/~/" path) 	dir = shellEscape base @@ -248,7 +250,7 @@ 	| otherwise = liftIO $ do 		ret <- tryIO $ Git.Config.read r 		case ret of-			Right r' -> return (toUUID $ Git.Config.get "annex.uuid" "" r', r')+			Right r' -> return (toUUID $ Git.Config.get configkeyUUID mempty r', r') 			Left _ -> return (NoUUID, r)  {- Converts a bup remote path spec into a Git.Repo. There are some
Remote/Directory.hs view
@@ -127,7 +127,7 @@  - We try more than one since we used to write to different hash  - directories. -} locations :: FilePath -> Key -> [FilePath]-locations d k = map (d </>) (keyPaths k)+locations d k = map (\f -> d </> fromRawFilePath f) (keyPaths k)  {- Returns the location off a Key in the directory. If the key is  - present, returns the location that is actually used, otherwise@@ -139,7 +139,8 @@  {- Directory where the file(s) for a key are stored. -} storeDir :: FilePath -> Key -> FilePath-storeDir d k = addTrailingPathSeparator $ d </> hashDirLower def k </> keyFile k+storeDir d k = addTrailingPathSeparator $+	d </> fromRawFilePath (hashDirLower def k) </> fromRawFilePath (keyFile k)  {- Check if there is enough free disk space in the remote's directory to  - store the key. Note that the unencrypted key size is checked. -}@@ -163,12 +164,13 @@ 	case chunkconfig of 		LegacyChunks chunksize -> Legacy.store chunksize finalizeStoreGeneric k b p tmpdir destdir 		_ -> do-			let tmpf = tmpdir </> keyFile k+			let tmpf = tmpdir </> kf 			meteredWriteFile p tmpf b 			finalizeStoreGeneric tmpdir destdir 			return True   where-	tmpdir = addTrailingPathSeparator $ d </> "tmp" </> keyFile k+	tmpdir = addTrailingPathSeparator $ d </> "tmp" </> kf+	kf = fromRawFilePath (keyFile k) 	destdir = storeDir d k  {- Passed a temp directory that contains the files that should be placed@@ -295,18 +297,18 @@ 	dest = exportPath d newloc  exportPath :: FilePath -> ExportLocation -> FilePath-exportPath d loc = d </> fromExportLocation loc+exportPath d loc = d </> fromRawFilePath (fromExportLocation loc)  {- Removes the ExportLocation's parent directory and its parents, so long as  - they're empty, up to but not including the topdir. -} removeExportLocation :: FilePath -> ExportLocation -> IO () removeExportLocation topdir loc = -	go (Just $ takeDirectory $ fromExportLocation loc) (Right ())+	go (Just $ takeDirectory $ fromRawFilePath $ fromExportLocation loc) (Right ())   where 	go _ (Left _e) = return () 	go Nothing _ = return () 	go (Just loc') _ = go (upFrom loc')-		=<< tryIO (removeDirectory $ exportPath topdir (mkExportLocation loc'))+		=<< tryIO (removeDirectory $ exportPath topdir (mkExportLocation (toRawFilePath loc')))  listImportableContentsM :: FilePath -> Annex (Maybe (ImportableContents (ContentIdentifier, ByteSize))) listImportableContentsM dir = catchMaybeIO $ liftIO $ do@@ -319,7 +321,7 @@ 		mkContentIdentifier f st >>= \case 			Nothing -> return Nothing 			Just cid -> do-				relf <- relPathDirToFile dir f+				relf <- toRawFilePath <$> relPathDirToFile dir f 				sz <- getFileSize' f st 				return $ Just (mkImportLocation relf, (cid, sz)) 
Remote/Directory/LegacyChunked.hs view
@@ -91,7 +91,7 @@ retrieve :: (FilePath -> Key -> [FilePath]) -> FilePath -> Preparer Retriever retrieve locations d basek a = withOtherTmp $ \tmpdir -> do 	showLongNote "This remote uses the deprecated chunksize setting. So this will be quite slow."-	let tmp = tmpdir </> keyFile basek ++ ".directorylegacy.tmp"+	let tmp = tmpdir </> fromRawFilePath (keyFile basek) ++ ".directorylegacy.tmp" 	a $ Just $ byteRetriever $ \k sink -> do 		liftIO $ void $ withStoredFiles d locations k $ \fs -> do 			forM_ fs $
Remote/External.hs view
@@ -5,6 +5,8 @@  - Licensed under the GNU AGPL version 3 or higher.  -} +{-# LANGUAGE OverloadedStrings #-}+ module Remote.External (remote) where  import Remote.External.Types@@ -16,7 +18,7 @@ import Types.UrlContents import qualified Git import Config-import Git.Config (isTrue, boolConfig)+import Git.Config (isTrueFalse, boolConfig) import Git.Env import Remote.Helper.Special import Remote.Helper.ExportImport@@ -155,7 +157,7 @@ 	(c', _encsetup) <- encryptionSetup c gc  	c'' <- case M.lookup "readonly" c of-		Just v | isTrue v == Just True -> do+		Just v | isTrueFalse v == Just True -> do 			setConfig (remoteConfig (fromJust (lookupName c)) "readonly") (boolConfig True) 			return c' 		_ -> do@@ -381,9 +383,9 @@ 	handleRemoteRequest (PROGRESS bytesprocessed) = 		maybe noop (\a -> liftIO $ a bytesprocessed) mp 	handleRemoteRequest (DIRHASH k) = -		send $ VALUE $ hashDirMixed def k+		send $ VALUE $ fromRawFilePath $ hashDirMixed def k 	handleRemoteRequest (DIRHASH_LOWER k) = -		send $ VALUE $ hashDirLower def k+		send $ VALUE $ fromRawFilePath $ hashDirLower def k 	handleRemoteRequest (SETCONFIG setting value) = 		liftIO $ atomically $ modifyTVar' (externalConfig st) $ 			M.insert setting value@@ -407,7 +409,8 @@ 		send $ CREDS (fst creds) (snd creds) 	handleRemoteRequest GETUUID = send $ 		VALUE $ fromUUID $ externalUUID external-	handleRemoteRequest GETGITDIR = send . VALUE =<< fromRepo Git.localGitDir+	handleRemoteRequest GETGITDIR = +		send . VALUE . fromRawFilePath =<< fromRepo Git.localGitDir 	handleRemoteRequest (SETWANTED expr) = 		preferredContentSet (externalUUID external) expr 	handleRemoteRequest GETWANTED = do
Remote/External/Types.hs view
@@ -384,12 +384,12 @@ 	deserialize = parseURI  instance Proto.Serializable ExportLocation where-	serialize = fromExportLocation-	deserialize = Just . mkExportLocation+	serialize = fromRawFilePath . fromExportLocation+	deserialize = Just . mkExportLocation . toRawFilePath  instance Proto.Serializable ExportDirectory where-	serialize = fromExportDirectory-	deserialize = Just . mkExportDirectory+	serialize = fromRawFilePath . fromExportDirectory+	deserialize = Just . mkExportDirectory . toRawFilePath  instance Proto.Serializable ExtensionList where 	serialize (ExtensionList l) = unwords l
Remote/GCrypt.hs view
@@ -5,6 +5,8 @@  - Licensed under the GNU AGPL version 3 or higher.  -} +{-# LANGUAGE OverloadedStrings #-}+ module Remote.GCrypt ( 	remote, 	chainGen,@@ -16,6 +18,7 @@ ) where  import qualified Data.Map as M+import qualified Data.ByteString as S import qualified Data.ByteString.Lazy as L import Control.Exception import Data.Default@@ -27,6 +30,7 @@ import Types.Crypto import Types.Creds import Types.Transfer+import Git.Types (ConfigKey(..), fromConfigKey, fromConfigValue) import qualified Git import qualified Git.Command import qualified Git.Config@@ -96,7 +100,7 @@ 			(Just remotename, Just c') -> do 				setGcryptEncryption c' remotename 				storeUUIDIn (remoteConfig baser "uuid") u'-				setConfig (ConfigKey $ Git.GCrypt.remoteConfigKey "gcrypt-id" remotename) gcryptid+				setConfig (Git.GCrypt.remoteConfigKey "gcrypt-id" remotename) gcryptid 				gen' r u' c' gc rs 			_ -> do 				warning $ "not using unknown gcrypt repository pointed to by remote " ++ Git.repoDescribe r@@ -159,11 +163,12 @@  rsyncTransport :: Git.Repo -> RemoteGitConfig -> Annex (Annex [CommandParam], String, AccessMethod) rsyncTransport r gc-	| "ssh://" `isPrefixOf` loc = sshtransport $ break (== '/') $ drop (length "ssh://") loc+	| sshprefix `isPrefixOf` loc = sshtransport $ break (== '/') $ drop (length sshprefix) loc 	| "//:" `isInfixOf` loc = othertransport 	| ":" `isInfixOf` loc = sshtransport $ separate (== ':') loc 	| otherwise = othertransport   where+	sshprefix = "ssh://" :: String 	loc = Git.repoLocation r 	sshtransport (host, path) = do 		let rsyncpath = if "/~/" `isPrefixOf` path@@ -252,7 +257,7 @@ 	| otherwise = localsetup r   where 	localsetup r' = do-		let setconfig k v = liftIO $ Git.Command.run [Param "config", Param k, Param v] r'+		let setconfig k v = liftIO $ Git.Command.run [Param "config", Param (fromConfigKey k), Param v] r' 		setconfig coreGCryptId gcryptid 		setconfig denyNonFastForwards (Git.Config.boolConfig False) 		return AccessDirect@@ -272,8 +277,8 @@ 			, Param tmpconfig 			] 		liftIO $ do-			void $ Git.Config.changeFile tmpconfig coreGCryptId gcryptid-			void $ Git.Config.changeFile tmpconfig denyNonFastForwards (Git.Config.boolConfig False)+			void $ Git.Config.changeFile tmpconfig coreGCryptId (encodeBS' gcryptid)+			void $ Git.Config.changeFile tmpconfig denyNonFastForwards (Git.Config.boolConfig' False) 		ok <- liftIO $ rsync $ opts ++ 			[ Param "--recursive" 			, Param $ tmp ++ "/"@@ -289,7 +294,7 @@ 		(\f p -> liftIO (boolSystem f p), return False) 		"gcryptsetup" [ Param gcryptid ] [] -	denyNonFastForwards = "receive.denyNonFastForwards"+	denyNonFastForwards = ConfigKey "receive.denyNonFastForwards"  accessShell :: Remote -> Bool accessShell = accessShellConfig . gitconfig@@ -326,7 +331,7 @@ 			Nothing -> noop 			Just (KeyIds { keyIds = ks}) -> do 				setConfig participants (unwords ks)-				let signingkey = ConfigKey $ Git.GCrypt.remoteSigningKey remotename+				let signingkey = Git.GCrypt.remoteSigningKey remotename 				cmd <- gpgCmd <$> Annex.getGitConfig 				skeys <- M.keys <$> liftIO (secretKeys cmd) 				case filter (`elem` ks) skeys of@@ -335,7 +340,7 @@ 	setConfig (remoteconfig Git.GCrypt.remotePublishParticipantConfigKey) 		(Git.Config.boolConfig True)   where-	remoteconfig n = ConfigKey $ n remotename+	remoteconfig n = n remotename  store :: Remote -> Remote.Rsync.RsyncOpts -> Storer store r rsyncopts k s p = do@@ -346,9 +351,9 @@ store' repo r rsyncopts 	| not $ Git.repoIsUrl repo =  		byteStorer $ \k b p -> guardUsable repo (return False) $ liftIO $ do-			let tmpdir = Git.repoLocation repo </> "tmp" </> keyFile k+			let tmpdir = Git.repoLocation repo </> "tmp" </> fromRawFilePath (keyFile k) 			void $ tryIO $ createDirectoryIfMissing True tmpdir-			let tmpf = tmpdir </> keyFile k+			let tmpf = tmpdir </> fromRawFilePath (keyFile k) 			meteredWriteFile p tmpf b 			let destdir = parentDir $ gCryptLocation repo k 			Remote.Directory.finalizeStoreGeneric tmpdir destdir@@ -417,7 +422,8 @@ {- Annexed objects are hashed using lower-case directories for max  - portability. -} gCryptLocation :: Git.Repo -> Key -> FilePath-gCryptLocation repo key = Git.repoLocation repo </> objectDir </> keyPath key (hashDirLower def)+gCryptLocation repo key = Git.repoLocation repo </> objectDir+	</> fromRawFilePath (keyPath key (hashDirLower def))  data AccessMethod = AccessDirect | AccessShell @@ -435,7 +441,7 @@ 	(genUUIDInNameSpace gCryptNameSpace <$>) . fst 		<$> getGCryptId fast r dummycfg -coreGCryptId :: String+coreGCryptId :: ConfigKey coreGCryptId = "core.gcrypt-id"  {- gcrypt repos set up by git-annex as special remotes have a@@ -457,9 +463,9 @@ 	| otherwise = return (Nothing, r)   where 	extract Nothing = (Nothing, r)-	extract (Just r') = (Git.Config.getMaybe coreGCryptId r', r')+	extract (Just r') = (fromConfigValue <$> Git.Config.getMaybe coreGCryptId r', r') -getConfigViaRsync :: Git.Repo -> RemoteGitConfig -> Annex (Either SomeException (Git.Repo, String))+getConfigViaRsync :: Git.Repo -> RemoteGitConfig -> Annex (Either SomeException (Git.Repo, S.ByteString)) getConfigViaRsync r gc = do 	(rsynctransport, rsyncurl, _) <- rsyncTransport r gc 	opts <- rsynctransport
Remote/Git.hs view
@@ -6,6 +6,7 @@  -}  {-# LANGUAGE CPP #-}+{-# LANGUAGE OverloadedStrings #-}  module Remote.Git ( 	remote,@@ -60,6 +61,7 @@ import Types.NumCopies import Annex.Action import Messages.Progress+import qualified Utility.RawFilePath as R  #ifndef mingw32_HOST_OS import Utility.FileMode@@ -68,6 +70,7 @@ import Control.Concurrent import Control.Concurrent.MSampleVar import qualified Data.Map as M+import qualified Data.ByteString as S import Network.URI  remote :: RemoteType@@ -86,14 +89,14 @@ 	rs <- mapM (tweakurl c) =<< Annex.getGitRemotes 	mapM (configRead autoinit) rs   where-	annexurl n = "remote." ++ n ++ ".annexurl"+	annexurl n = Git.ConfigKey ("remote." <> encodeBS' n <> ".annexurl") 	tweakurl c r = do 		let n = fromJust $ Git.remoteName r 		case M.lookup (annexurl n) c of 			Nothing -> return r 			Just url -> inRepo $ \g -> 				Git.Construct.remoteNamed n $-					Git.Construct.fromRemoteLocation url g+					Git.Construct.fromRemoteLocation (Git.fromConfigValue url) g  {- Git remotes are normally set up using standard git command, not  - git-annex initremote and enableremote.@@ -254,7 +257,7 @@ 		v <- liftIO $ Git.Config.fromPipe r cmd params 		case v of 			Right (r', val) -> do-				unless (isUUIDConfigured r' || null val) $ do+				unless (isUUIDConfigured r' || S.null val) $ do 					warning $ "Failed to get annex.uuid configuration of repository " ++ Git.repoDescribe r 					warning $ "Instead, got: " ++ show val 					warning $ "This is unexpected; please check the network transport!"@@ -391,9 +394,9 @@ 		| remoteAnnexBare remoteconfig == Just False = reverse (annexLocations gc key) 		| otherwise = annexLocations gc key #ifndef mingw32_HOST_OS-	locs' = locs+	locs' = map fromRawFilePath locs #else-	locs' = map (replace "\\" "/") locs+	locs' = map (replace "\\" "/" . fromRawFilePath) locs #endif 	remoteconfig = gitconfig r @@ -549,7 +552,7 @@ 		u <- getUUID 		let AssociatedFile afile = file 		let fields = (Fields.remoteUUID, fromUUID u)-			: maybe [] (\f -> [(Fields.associatedFile, f)]) afile+			: maybe [] (\f -> [(Fields.associatedFile, fromRawFilePath f)]) afile 		Just (cmd, params) <- Ssh.git_annex_shell ConsumeStdin 			repo "transferinfo"  			[Param $ serializeKey key] fields@@ -597,9 +600,9 @@ 	| not $ Git.repoIsUrl repo = guardUsable repo (return False) $ do 		gc <- getGitConfigFromState st 		loc <- liftIO $ gitAnnexLocation key repo gc-		liftIO $ ifM (doesFileExist loc)+		liftIO $ ifM (R.doesPathExist loc) 			( do-				absloc <- absPath loc+				absloc <- absPath (fromRawFilePath loc) 				catchBoolIO $ do 					createSymbolicLink absloc file 					return True@@ -678,8 +681,8 @@ 		r' <- Git.Config.read r 		environ <- getEnvironment 		let environ' = addEntries -			[ ("GIT_WORK_TREE", Git.repoPath r')-			, ("GIT_DIR", Git.localGitDir r')+			[ ("GIT_WORK_TREE", fromRawFilePath $ Git.repoPath r')+			, ("GIT_DIR", fromRawFilePath $ Git.localGitDir r') 			] environ 		batchCommandEnv program (Param "fsck" : params) (Just environ') @@ -854,13 +857,13 @@   where 	go 		| remoteAnnexCheckUUID gc = return-			(return True, return (r, extractGitConfig r))+			(return True, return (r, extractGitConfig FromGitConfig r)) 		| otherwise = do 			rv <- liftIO newEmptyMVar 			let getrepo = ifM (liftIO $ isEmptyMVar rv) 				( do 					r' <- tryGitConfigRead False r-					let t = (r', extractGitConfig r')+					let t = (r', extractGitConfig FromGitConfig r') 					void $ liftIO $ tryPutMVar rv t 					return t 				, liftIO $ readMVar rv
Remote/GitLFS.hs view
@@ -5,6 +5,8 @@  - Licensed under the GNU AGPL version 3 or higher.  -} +{-# LANGUAGE OverloadedStrings #-}+ module Remote.GitLFS (remote, gen, configKnownUrl) where  import Annex.Common@@ -153,7 +155,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 (ConfigKey ("remote." ++ getRemoteName c ++ ".url")) url+	setConfig (Git.ConfigKey ("remote." <> encodeBS' (getRemoteName c) <> ".url")) url 	return (c', u)   where 	url = fromMaybe (giveup "Specify url=") (M.lookup "url" c)@@ -185,9 +187,9 @@ 				set "config-uuid" (fromUUID cu) r' 			Nothing -> return r' 	set k v r' = do-		let ck@(ConfigKey k') = remoteConfig r' k-		setConfig ck v-		return $ Git.Config.store' k' v r'+		let k' = remoteConfig r' k+		setConfig k' v+		return $ Git.Config.store' k' (Git.ConfigValue (encodeBS' v)) r'  data LFSHandle = LFSHandle 	{ downloadEndpoint :: Maybe LFS.Endpoint
Remote/Helper/Chunked/Legacy.hs view
@@ -77,7 +77,7 @@ 		warningIO (show e) 		return False -	basef = tmp ++ keyFile key+	basef = tmp ++ fromRawFilePath (keyFile key) 	tmpdests = map (basef ++ ) chunkStream  {- Given a list of destinations to use, chunks the data according to the
Remote/Helper/Git.hs view
@@ -20,7 +20,7 @@ localpathCalc :: Git.Repo -> Maybe FilePath localpathCalc r 	| availabilityCalc r == GloballyAvailable = Nothing-	| otherwise = Just $ Git.repoPath r+	| otherwise = Just $ fromRawFilePath $ Git.repoPath r  availabilityCalc :: Git.Repo -> Availability availabilityCalc r@@ -36,7 +36,7 @@  gitRepoInfo :: Remote -> Annex [(String, String)] gitRepoInfo r = do-	d <- fromRepo Git.localGitDir+	d <- fromRawFilePath <$> fromRepo Git.localGitDir 	mtimes <- liftIO $ mapM (modificationTime <$$> getFileStatus) 		=<< dirContentsRecursive (d </> "refs" </> "remotes" </> Remote.name r) 	let lastsynctime = case mtimes of
Remote/Helper/Special.hs view
@@ -5,6 +5,8 @@  - Licensed under the GNU AGPL version 3 or higher.  -} +{-# LANGUAGE OverloadedStrings #-}+ module Remote.Helper.Special ( 	findSpecialRemotes, 	gitConfigSpecialRemote,@@ -51,7 +53,9 @@ import Messages.Progress import qualified Git import qualified Git.Construct+import Git.Types +import qualified Data.ByteString as S import qualified Data.ByteString.Lazy as L import qualified Data.Map as M @@ -65,14 +69,17 @@ 	liftIO $ mapM construct $ remotepairs m   where 	remotepairs = M.toList . M.filterWithKey match-	construct (k,_) = Git.Construct.remoteNamedFromKey k (pure Git.Construct.fromUnknown)-	match k _ = "remote." `isPrefixOf` k && (".annex-"++s) `isSuffixOf` k+	construct (k,_) = Git.Construct.remoteNamedFromKey k+		(pure Git.Construct.fromUnknown)+	match (ConfigKey k) _ =+		"remote." `S.isPrefixOf` k +		&& (".annex-" <> encodeBS' s) `S.isSuffixOf` k  {- Sets up configuration for a special remote in .git/config. -} gitConfigSpecialRemote :: UUID -> RemoteConfig -> [(String, String)] -> Annex () gitConfigSpecialRemote u c cfgs = do 	forM_ cfgs $ \(k, v) -> -		setConfig (remoteConfig c k) v+		setConfig (remoteConfig c (encodeBS' k)) v 	storeUUIDIn (remoteConfig c "uuid") u  -- RetrievalVerifiableKeysSecure unless overridden by git config.
Remote/Helper/Ssh.hs view
@@ -65,7 +65,7 @@ 		let params' = if debug 			then Param "--debug" : params 			else params-		return (Param command : File dir : params')+		return (Param command : File (fromRawFilePath dir) : params') 	uuidcheck NoUUID = [] 	uuidcheck u@(UUID _) = ["--uuid", fromUUID u] 	fieldopts@@ -137,7 +137,7 @@ 		-- Send direct field for unlocked content, for backwards 		-- compatability. 		: (Fields.direct, if unlocked then "1" else "")-		: maybe [] (\f -> [(Fields.associatedFile, f)]) afile+		: maybe [] (\f -> [(Fields.associatedFile, fromRawFilePath f)]) afile 	repo <- getRepo r 	Just (shellcmd, shellparams) <- git_annex_shell ConsumeStdin repo 		(if direction == Download then "sendkey" else "recvkey")
Remote/Hook.hs view
@@ -11,6 +11,7 @@ import Types.Remote import Types.Creds import qualified Git+import Git.Types (fromConfigKey, fromConfigValue) import Config import Config.Cost import Annex.UUID@@ -103,23 +104,24 @@ 		] 	fileenv Nothing = [] 	fileenv (Just file) =  [envvar "FILE" file]-	hashbits = map takeDirectory $ splitPath $ hashDirMixed def k+	hashbits = map takeDirectory $ splitPath $+		fromRawFilePath $ hashDirMixed def k  lookupHook :: HookName -> Action -> Annex (Maybe String) lookupHook hookname action = do-	command <- getConfig (annexConfig hook) ""+	command <- fromConfigValue <$> getConfig hook mempty 	if null command 		then do-			fallback <- getConfig (annexConfig hookfallback) ""+			fallback <- fromConfigValue <$> getConfig hookfallback mempty 			if null fallback 				then do-					warning $ "missing configuration for " ++ hook ++ " or " ++ hookfallback+					warning $ "missing configuration for " ++ fromConfigKey hook ++ " or " ++ fromConfigKey hookfallback 					return Nothing 				else return $ Just fallback 		else return $ Just command   where-	hook = hookname ++ "-" ++ action ++ "-hook"-	hookfallback = hookname ++ "-hook"+	hook = annexConfig $ encodeBS' $ hookname ++ "-" ++ action ++ "-hook"+	hookfallback = annexConfig $ encodeBS' $ hookname ++ "-hook"  runHook :: HookName -> Action -> Key -> Maybe FilePath -> Annex Bool -> Annex Bool runHook hook action k f a = maybe (return False) run =<< lookupHook hook action
Remote/Rsync.hs view
@@ -183,7 +183,7 @@ store :: RsyncOpts -> Key -> FilePath -> MeterUpdate -> Annex Bool store o k src meterupdate = storeGeneric o meterupdate basedest populatedest   where-	basedest = Prelude.head (keyPaths k)+	basedest = fromRawFilePath $ Prelude.head (keyPaths k) 	populatedest dest = liftIO $ if canrename 		then do 			rename src dest@@ -222,11 +222,11 @@ remove o k = removeGeneric o includes   where 	includes = concatMap use dirHashes-	use h = let dir = h def k in+	use h = let dir = fromRawFilePath (h def k) in 		[ parentDir dir 		, dir 		-- match content directory and anything in it-		, dir </> keyFile k </> "***"+		, dir </> fromRawFilePath (keyFile k) </> "***" 		]  {- An empty directory is rsynced to make it delete. Everything is excluded,@@ -268,22 +268,22 @@ storeExportM o src _k loc meterupdate = 	storeGeneric o meterupdate basedest populatedest   where-	basedest = fromExportLocation loc+	basedest = fromRawFilePath (fromExportLocation loc) 	populatedest = liftIO . createLinkOrCopy src  retrieveExportM :: RsyncOpts -> Key -> ExportLocation -> FilePath -> MeterUpdate -> Annex Bool retrieveExportM o _k loc dest p = rsyncRetrieve o [rsyncurl] dest (Just p)   where-	rsyncurl = mkRsyncUrl o (fromExportLocation loc)+	rsyncurl = mkRsyncUrl o (fromRawFilePath (fromExportLocation loc))  checkPresentExportM :: RsyncOpts -> Key -> ExportLocation -> Annex Bool checkPresentExportM o _k loc = checkPresentGeneric o [rsyncurl]   where-	rsyncurl = mkRsyncUrl o (fromExportLocation loc)+	rsyncurl = mkRsyncUrl o (fromRawFilePath (fromExportLocation loc))  removeExportM :: RsyncOpts -> Key -> ExportLocation -> Annex Bool removeExportM o _k loc =-	removeGeneric o (includes (fromExportLocation loc))+	removeGeneric o $ includes $ fromRawFilePath $ fromExportLocation loc   where 	includes f = f : case upFrom f of 		Nothing -> []@@ -292,7 +292,7 @@ removeExportDirectoryM :: RsyncOpts -> ExportDirectory -> Annex Bool removeExportDirectoryM o ed = removeGeneric o (allbelow d : includes d)   where-	d = fromExportDirectory ed+	d = fromRawFilePath $ fromExportDirectory ed 	allbelow f = f </> "***" 	includes f = f : case upFrom f of 		Nothing -> []
Remote/Rsync/RsyncUrl.hs view
@@ -13,14 +13,15 @@ import Annex.Locations import Utility.Rsync import Utility.SafeCommand--import Data.Default-import System.FilePath.Posix+import Utility.FileSystemEncoding+import Annex.DirHashes #ifdef mingw32_HOST_OS import Utility.Split #endif-import Annex.DirHashes +import Data.Default+import System.FilePath.Posix+ type RsyncUrl = String  data RsyncOpts = RsyncOpts@@ -42,8 +43,8 @@ rsyncUrls :: RsyncOpts -> Key -> [RsyncUrl] rsyncUrls o k = map use dirHashes   where-	use h = rsyncUrl o </> hash h </> rsyncEscape o (f </> f)-	f = keyFile k+	use h = rsyncUrl o </> fromRawFilePath (hash h) </> rsyncEscape o (f </> f)+	f = fromRawFilePath (keyFile k) #ifndef mingw32_HOST_OS 	hash h = h def k #else
Remote/S3.hs view
@@ -881,7 +881,8 @@ 		_ -> getFilePrefix c ++ s  getBucketExportLocation :: RemoteConfig -> ExportLocation -> BucketObject-getBucketExportLocation c loc = getFilePrefix c ++ fromExportLocation loc+getBucketExportLocation c loc =+	getFilePrefix c ++ fromRawFilePath (fromExportLocation loc)  getBucketImportLocation :: RemoteConfig -> BucketObject -> Maybe ImportLocation getBucketImportLocation c obj@@ -889,7 +890,8 @@ 	| obj == uuidfile = Nothing 	-- Only import files that are under the fileprefix, when 	-- one is configured.-	| prefix `isPrefixOf` obj = Just $ mkImportLocation $ drop prefixlen obj+	| prefix `isPrefixOf` obj = Just $ mkImportLocation $+		toRawFilePath $ drop prefixlen obj 	| otherwise = Nothing   where 	prefix = getFilePrefix c
Remote/WebDAV.hs view
@@ -229,7 +229,7 @@  removeExportDirectoryDav :: Remote -> ExportDirectory -> Annex Bool removeExportDirectoryDav r dir = withDAVHandle r $ \mh -> runExport mh $ \_dav -> do-	let d = fromExportDirectory dir+	let d = fromRawFilePath $ fromExportDirectory dir 	debugDav $ "delContent " ++ d 	safely (inLocation d delContentM) 		>>= maybe (return False) (const $ return True)
Remote/WebDAV/DavLocation.hs view
@@ -17,6 +17,7 @@ #ifdef mingw32_HOST_OS import Utility.Split #endif+import Utility.FileSystemEncoding  import System.FilePath.Posix -- for manipulating url paths import Network.Protocol.HTTP.DAV (inDAVLocation, DAVT)@@ -35,29 +36,31 @@  {- The directory where files(s) for a key are stored. -} keyDir :: Key -> DavLocation-keyDir k = addTrailingPathSeparator $ hashdir </> keyFile k+keyDir k = addTrailingPathSeparator $ hashdir </> fromRawFilePath (keyFile k)   where #ifndef mingw32_HOST_OS-	hashdir = hashDirLower def k+	hashdir = fromRawFilePath $ hashDirLower def k #else-	hashdir = replace "\\" "/" (hashDirLower def k)+	hashdir = replace "\\" "/" (fromRawFilePath $ hashDirLower def k) #endif  keyLocation :: Key -> DavLocation-keyLocation k = keyDir k ++ keyFile k+keyLocation k = keyDir k ++ fromRawFilePath (keyFile k)  {- Paths containing # or ? cannot be represented in an url, so fails on  - those. -} exportLocation :: ExportLocation -> Either String DavLocation exportLocation l =-	let p = fromExportLocation l-	in if any (`elem` p) ['#', '?']+	let p = fromRawFilePath $ fromExportLocation l+	in if any (`elem` p) illegalinurl 		then Left ("Cannot store file containing '#' or '?' on webdav: " ++ p) 		else Right p+  where+	illegalinurl = ['#', '?'] :: [Char]  {- Where we store temporary data for a key as it's being uploaded. -} keyTmpLocation :: Key -> DavLocation-keyTmpLocation = tmpLocation . keyFile+keyTmpLocation = tmpLocation . fromRawFilePath . keyFile  tmpLocation :: FilePath -> DavLocation tmpLocation f = "git-annex-webdav-tmp-" ++ f
Test.hs view
@@ -624,7 +624,7 @@ 	git_annex "get" [annexedfile] @? "get of file failed" 	git_annex "unlock" [annexedfile] @? "unlock failed" 	annexeval $ do-		Just k <- Annex.WorkTree.lookupFile annexedfile+		Just k <- Annex.WorkTree.lookupFile (toRawFilePath annexedfile) 		Database.Keys.removeInodeCaches k 		Database.Keys.closeDb 		liftIO . nukeFile =<< Annex.fromRepo Annex.Locations.gitAnnexKeysDbIndexCache@@ -1146,7 +1146,7 @@ 			@? (what ++ " too many variant files in: " ++ show v) 		indir d $ do 			git_annex "get" (conflictor:v) @? ("get failed in " ++ what)-			git_annex_expectoutput "find" [conflictor] [Git.FilePath.toInternalGitPath subfile]+			git_annex_expectoutput "find" [conflictor] [fromRawFilePath (Git.FilePath.toInternalGitPath (toRawFilePath subfile))] 			git_annex_expectoutput "find" v v  {- Check merge conflict resolution when both repos start with an annexed@@ -1343,7 +1343,7 @@   where 	conflictor = "conflictor" 	check_is_link f what = do-		git_annex_expectoutput "find" ["--include=*", f] [Git.FilePath.toInternalGitPath f]+		git_annex_expectoutput "find" ["--include=*", f] [fromRawFilePath (Git.FilePath.toInternalGitPath (toRawFilePath f))] 		l <- annexeval $ Annex.inRepo $ Git.LsTree.lsTreeFiles Git.Ref.headRef [f] 		all (\i -> Git.Types.toTreeItemType (Git.LsTree.mode i) == Just Git.Types.TreeSymlink) l 			@? (what ++ " " ++ f ++ " lost symlink bit after merge: " ++ show l)@@ -1598,7 +1598,7 @@ 			(c,k) <- annexeval $ do 				uuid <- Remote.nameToUUID "foo" 				rs <- Logs.Remote.readRemoteLog-				Just k <- Annex.WorkTree.lookupFile annexedfile+				Just k <- Annex.WorkTree.lookupFile (toRawFilePath annexedfile) 				return (fromJust $ M.lookup uuid rs, k) 			let key = if scheme `elem` ["hybrid","pubkey"] 					then Just $ Utility.Gpg.KeyIds [Utility.Gpg.testKeyId]@@ -1638,7 +1638,8 @@ 		checkFile mvariant filename = 			Utility.Gpg.checkEncryptionFile gpgcmd filename $ 				if mvariant == Just Types.Crypto.PubKey then ks else Nothing-		serializeKeys cipher = Annex.Locations.keyPaths .+		serializeKeys cipher = map fromRawFilePath . +			Annex.Locations.keyPaths . 			Crypto.encryptKey Types.Crypto.HmacSha1 cipher #else test_crypto = putStrLn "gpg testing not implemented on Windows"
Test/Framework.hs view
@@ -23,6 +23,7 @@ import qualified Backend import qualified Git.CurrentRepo import qualified Git.Construct+import qualified Git.Types import qualified Types.KeySource import qualified Types.Backend import qualified Types@@ -88,8 +89,9 @@  with_ssh_origin :: (Assertion -> Assertion) -> (Assertion -> Assertion) with_ssh_origin cloner a = cloner $ do-	origindir <- absPath-		=<< annexeval (Config.getConfig (Config.ConfigKey config) "/dev/null")+	let k = Git.Types.ConfigKey (encodeBS' config)+	let v = Git.Types.ConfigValue (toRawFilePath "/dev/null")+	origindir <- absPath . Git.Types.fromConfigValue =<< annexeval (Config.getConfig k v) 	let originurl = "localhost:" ++ origindir 	boolSystem "git" [Param "config", Param config, Param originurl] @? "git config failed" 	a@@ -254,7 +256,7 @@  checklink :: FilePath -> Assertion checklink f = ifM (annexeval Config.crippledFileSystem)-	( (isJust <$> annexeval (Annex.Link.getAnnexLinkTarget f))+	( (isJust <$> annexeval (Annex.Link.getAnnexLinkTarget (toRawFilePath f))) 		@? f ++ " is not a (crippled) symlink" 	, do 		s <- getSymbolicLinkStatus f@@ -312,7 +314,7 @@ checklocationlog :: FilePath -> Bool -> Assertion checklocationlog f expected = do 	thisuuid <- annexeval Annex.UUID.getUUID-	r <- annexeval $ Annex.WorkTree.lookupFile f+	r <- annexeval $ Annex.WorkTree.lookupFile (toRawFilePath f) 	case r of 		Just k -> do 			uuids <- annexeval $ Remote.keyLocations k@@ -323,11 +325,11 @@ checkbackend :: FilePath -> Types.Backend -> Assertion checkbackend file expected = do 	b <- annexeval $ maybe (return Nothing) (Backend.getBackend file) -		=<< Annex.WorkTree.lookupFile file+		=<< Annex.WorkTree.lookupFile (toRawFilePath file) 	assertEqual ("backend for " ++ file) (Just expected) b  checkispointerfile :: FilePath -> Assertion-checkispointerfile f = unlessM (isJust <$> Annex.Link.isPointerFile f) $+checkispointerfile f = unlessM (isJust <$> Annex.Link.isPointerFile (toRawFilePath f)) $ 	assertFailure $ f ++ " is not a pointer file"  inlocationlog :: FilePath -> Assertion
Types/ActionItem.hs view
@@ -12,15 +12,17 @@ import Key import Types.Transfer import Git.FilePath+import Utility.FileSystemEncoding  import Data.Maybe+import qualified Data.ByteString as S  data ActionItem  	= ActionItemAssociatedFile AssociatedFile Key 	| ActionItemKey Key 	| ActionItemBranchFilePath BranchFilePath Key 	| ActionItemFailedTransfer Transfer TransferInfo-	| ActionItemWorkTreeFile FilePath+	| ActionItemWorkTreeFile RawFilePath 	| ActionItemOther (Maybe String) 	-- Use to avoid more than one thread concurrently processing the 	-- same Key.@@ -39,10 +41,10 @@ instance MkActionItem (Key, AssociatedFile) where 	mkActionItem = uncurry $ flip ActionItemAssociatedFile -instance MkActionItem (Key, FilePath) where+instance MkActionItem (Key, RawFilePath) where 	mkActionItem (key, file) = ActionItemAssociatedFile (AssociatedFile (Just file)) key -instance MkActionItem (FilePath, Key) where+instance MkActionItem (RawFilePath, Key) where 	mkActionItem (file, key) = mkActionItem (key, file)  instance MkActionItem Key where@@ -54,16 +56,16 @@ instance MkActionItem (Transfer, TransferInfo) where 	mkActionItem = uncurry ActionItemFailedTransfer -actionItemDesc :: ActionItem -> String+actionItemDesc :: ActionItem -> S.ByteString actionItemDesc (ActionItemAssociatedFile (AssociatedFile (Just f)) _) = f actionItemDesc (ActionItemAssociatedFile (AssociatedFile Nothing) k) = -	serializeKey k-actionItemDesc (ActionItemKey k) = serializeKey k+	serializeKey' k+actionItemDesc (ActionItemKey k) = serializeKey' k actionItemDesc (ActionItemBranchFilePath bfp _) = descBranchFilePath bfp actionItemDesc (ActionItemFailedTransfer t i) = actionItemDesc $ 	ActionItemAssociatedFile (associatedFile i) (transferKey t) actionItemDesc (ActionItemWorkTreeFile f) = f-actionItemDesc (ActionItemOther s) = fromMaybe "" s+actionItemDesc (ActionItemOther s) = encodeBS' (fromMaybe "" s) actionItemDesc (OnlyActionOn _ ai) = actionItemDesc ai  actionItemKey :: ActionItem -> Maybe Key@@ -75,7 +77,7 @@ actionItemKey (ActionItemOther _) = Nothing actionItemKey (OnlyActionOn _ ai) = actionItemKey ai -actionItemWorkTreeFile :: ActionItem -> Maybe FilePath+actionItemWorkTreeFile :: ActionItem -> Maybe RawFilePath actionItemWorkTreeFile (ActionItemAssociatedFile (AssociatedFile af) _) = af actionItemWorkTreeFile (ActionItemWorkTreeFile f) = Just f actionItemWorkTreeFile (OnlyActionOn _ ai) = actionItemWorkTreeFile ai
Types/Difference.hs view
@@ -5,6 +5,8 @@  - Licensed under the GNU AGPL version 3 or higher.  -} +{-# LANGUAGE OverloadedStrings #-}+ module Types.Difference ( 	Difference(..), 	Differences(..),@@ -20,9 +22,11 @@ import Utility.PartialPrelude import qualified Git import qualified Git.Config+import Git.Types  import Data.Maybe import Data.Monoid+import qualified Data.ByteString as B import qualified Data.Set as S import qualified Data.Semigroup as Sem import Prelude@@ -92,11 +96,11 @@ getDifferences r = mkDifferences $ S.fromList $ 	mapMaybe getmaybe [minBound .. maxBound]   where-	getmaybe d = case Git.Config.isTrue =<< Git.Config.getMaybe (differenceConfigKey d) r of+	getmaybe d = case Git.Config.isTrueFalse' =<< Git.Config.getMaybe (differenceConfigKey d) r of 		Just True -> Just d 		_ -> Nothing -differenceConfigKey :: Difference -> String+differenceConfigKey :: Difference -> ConfigKey differenceConfigKey ObjectHashLower = tunable "objecthashlower" differenceConfigKey OneLevelObjectHash = tunable "objecthash1" differenceConfigKey OneLevelBranchHash = tunable "branchhash1"@@ -104,8 +108,8 @@ differenceConfigVal :: Difference -> String differenceConfigVal _ = Git.Config.boolConfig True -tunable :: String -> String-tunable k = "annex.tune." ++ k+tunable :: B.ByteString -> ConfigKey+tunable k = ConfigKey ("annex.tune." <> k)  hasDifference :: Difference -> Differences -> Bool hasDifference _ UnknownDifferences = False
Types/Distribution.hs view
@@ -12,7 +12,7 @@ import Types.Key import Key import Data.Time.Clock-import Git.Config (isTrue, boolConfig)+import Git.Config (isTrueFalse, boolConfig)  import Control.Applicative import Prelude@@ -71,7 +71,7 @@ toAutoUpgrade Nothing = AskUpgrade toAutoUpgrade (Just s) 	| s == "ask" = AskUpgrade-	| isTrue s == Just True = AutoUpgrade+	| isTrueFalse s == Just True = AutoUpgrade 	| otherwise = NoAutoUpgrade  fromAutoUpgrade :: AutoUpgrade -> String
Types/Export.hs view
@@ -17,38 +17,39 @@  import Git.FilePath import Utility.Split+import Utility.FileSystemEncoding  import qualified System.FilePath.Posix as Posix  -- A location on a remote that a key can be exported to.--- The FilePath will be relative to the top of the remote,+-- The RawFilePath will be relative to the top of the remote, -- and uses unix-style path separators.-newtype ExportLocation = ExportLocation FilePath+newtype ExportLocation = ExportLocation RawFilePath 	deriving (Show, Eq) -mkExportLocation :: FilePath -> ExportLocation+mkExportLocation :: RawFilePath -> ExportLocation mkExportLocation = ExportLocation . toInternalGitPath -fromExportLocation :: ExportLocation -> FilePath+fromExportLocation :: ExportLocation -> RawFilePath fromExportLocation (ExportLocation f) = f -newtype ExportDirectory = ExportDirectory FilePath+newtype ExportDirectory = ExportDirectory RawFilePath 	deriving (Show, Eq) -mkExportDirectory :: FilePath -> ExportDirectory+mkExportDirectory :: RawFilePath -> ExportDirectory mkExportDirectory = ExportDirectory . toInternalGitPath -fromExportDirectory :: ExportDirectory -> FilePath+fromExportDirectory :: ExportDirectory -> RawFilePath fromExportDirectory (ExportDirectory f) = f  -- | All subdirectories down to the ExportLocation, with the deepest ones -- last. Does not include the top of the export. exportDirectories :: ExportLocation -> [ExportDirectory] exportDirectories (ExportLocation f) =-	map (ExportDirectory . Posix.joinPath . reverse) (subs [] dirs)+	map (ExportDirectory . encodeBS . Posix.joinPath . reverse) (subs [] dirs)   where 	subs _ [] = [] 	subs ps (d:ds) = (d:ps) : subs (d:ps) ds  	dirs = map Posix.dropTrailingPathSeparator $-		dropFromEnd 1 $ Posix.splitPath f+		dropFromEnd 1 $ Posix.splitPath $ decodeBS f
Types/FileMatcher.hs view
@@ -12,6 +12,7 @@ import Types.Mime import Utility.Matcher (Matcher, Token) import Utility.FileSize+import Utility.FileSystemEncoding  import Control.Monad.IO.Class import qualified Data.Map as M@@ -24,9 +25,9 @@ 	| MatchingInfo ProvidedInfo  data FileInfo = FileInfo-	{ currFile :: FilePath+	{ currFile :: RawFilePath 	-- ^ current path to the file, for operations that examine it-	, matchFile :: FilePath+	, matchFile :: RawFilePath 	-- ^ filepath to match on; may be relative to top of repo or cwd 	} 
Types/GitConfig.hs view
@@ -5,8 +5,11 @@  - Licensed under the GNU AGPL version 3 or higher.  -} +{-# LANGUAGE OverloadedStrings #-}+ module Types.GitConfig (  	Configurable(..),+	ConfigSource(..), 	GitConfig(..), 	extractGitConfig, 	mergeGitConfig,@@ -44,13 +47,17 @@ -- | A configurable value, that may not be fully determined yet because -- the global git config has not yet been loaded. data Configurable a-	= HasConfig a-	-- ^ Value is fully determined.+	= HasGitConfig a+	-- ^ The git config has a value.+	| HasGlobalConfig a+	-- ^ The global config has a value (and the git config does not). 	| DefaultConfig a 	-- ^ A default value is known, but not all config sources 	-- have been read yet. 	deriving (Show) +data ConfigSource = FromGitConfig | FromGlobalConfig+ {- Main git-annex settings. Each setting corresponds to a git-config key  - such as annex.foo -} data GitConfig = GitConfig@@ -78,7 +85,7 @@ 	, annexYoutubeDlOptions :: [String] 	, annexAriaTorrentOptions :: [String] 	, annexCrippledFileSystem :: Bool-	, annexLargeFiles :: Maybe String+	, annexLargeFiles :: Configurable (Maybe String) 	, annexGitAddToAnnex :: Bool 	, annexAddSmallFiles :: Bool 	, annexFsckNudge :: Bool@@ -95,7 +102,7 @@ 	, annexVerify :: Bool 	, annexPidLock :: Bool 	, annexPidLockTimeout :: Seconds-	, annexAddUnlocked :: Bool+	, annexAddUnlocked :: Configurable (Maybe String) 	, annexSecureHashesOnly :: Bool 	, annexRetry :: Maybe Integer 	, annexRetryDelay :: Maybe Seconds@@ -114,8 +121,8 @@ 	, gpgCmd :: GpgCmd 	} -extractGitConfig :: Git.Repo -> GitConfig-extractGitConfig r = GitConfig+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")@@ -149,7 +156,8 @@ 	, annexYoutubeDlOptions = getwords (annex "youtube-dl-options") 	, annexAriaTorrentOptions = getwords (annex "aria-torrent-options") 	, annexCrippledFileSystem = getbool (annex "crippledfilesystem") False-	, annexLargeFiles = getmaybe (annex "largefiles")+	, annexLargeFiles = configurable Nothing $+		fmap Just $ getmaybe (annex "largefiles") 	, annexGitAddToAnnex = getbool (annex "gitaddtoannex") True 	, annexAddSmallFiles = getbool (annex "addsmallfiles") True 	, annexFsckNudge = getbool (annex "fscknudge") True@@ -169,7 +177,8 @@ 	, annexPidLock = getbool (annex "pidlock") False 	, annexPidLockTimeout = Seconds $ fromMaybe 300 $ 		getmayberead (annex "pidlocktimeout")-	, annexAddUnlocked = getbool (annex "addunlocked") False+	, annexAddUnlocked = configurable Nothing $+		fmap Just $ getmaybe (annex "addunlocked") 	, annexSecureHashesOnly = getbool (annex "securehashesonly") False 	, annexRetry = getmayberead (annex "retry") 	, annexRetryDelay = Seconds@@ -199,16 +208,19 @@ 	}   where 	getbool k d = fromMaybe d $ getmaybebool k-	getmaybebool k = Git.Config.isTrue =<< getmaybe k+	getmaybebool k = Git.Config.isTrueFalse' =<< getmaybe' k 	getmayberead k = readish =<< getmaybe k-	getmaybe k = Git.Config.getMaybe k r-	getlist k = Git.Config.getList k r+	getmaybe = fmap fromConfigValue . getmaybe'+	getmaybe' k = Git.Config.getMaybe k r+	getlist k = map fromConfigValue $ Git.Config.getList k r 	getwords k = fromMaybe [] $ words <$> getmaybe k  	configurable d Nothing = DefaultConfig d-	configurable _ (Just v) = HasConfig v+	configurable _ (Just v) = case configsource of+		FromGitConfig -> HasGitConfig v+		FromGlobalConfig -> HasGlobalConfig v -	annex k = "annex." ++ k+	annex k = ConfigKey $ "annex." <> k 			 	onemegabyte = 1000000 @@ -218,13 +230,17 @@ mergeGitConfig gitconfig repoglobals = gitconfig 	{ annexAutoCommit = merge annexAutoCommit 	, annexSyncContent = merge annexSyncContent+	, annexResolveMerge = merge annexResolveMerge+	, annexLargeFiles = merge annexLargeFiles+	, annexAddUnlocked = merge annexAddUnlocked 	}   where 	merge f = case f gitconfig of-		HasConfig v -> HasConfig v+		HasGitConfig v -> HasGitConfig v 		DefaultConfig d -> case f repoglobals of-			HasConfig v -> HasConfig v-			DefaultConfig _ -> HasConfig d+			HasGlobalConfig v -> HasGlobalConfig v+			_ -> HasGitConfig d+		HasGlobalConfig v -> HasGlobalConfig v  {- 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@@ -340,14 +356,16 @@ 		}   where 	getbool k d = fromMaybe d $ getmaybebool k-	getmaybebool k = Git.Config.isTrue =<< getmaybe k+	getmaybebool k = Git.Config.isTrueFalse' =<< getmaybe' k 	getmayberead k = readish =<< getmaybe k-	getmaybe k = mplus (Git.Config.getMaybe (key k) r)+	getmaybe = fmap fromConfigValue . getmaybe'+	getmaybe' k = mplus (Git.Config.getMaybe (key k) r) 		(Git.Config.getMaybe (remotekey k) r) 	getoptions k = fromMaybe [] $ words <$> getmaybe k -	key k = "annex." ++ k-	remotekey k = "remote." ++ remotename ++ ".annex-" ++ k+	key k = ConfigKey $ "annex." <> k+	remotekey k = ConfigKey $+		"remote." <> encodeBS' remotename <> ".annex-" <> k  notempty :: Maybe String -> Maybe String	 notempty Nothing = Nothing
Types/Import.hs view
@@ -19,10 +19,10 @@  - location on the remote. -} type ImportLocation = ExportLocation -mkImportLocation :: FilePath -> ImportLocation+mkImportLocation :: RawFilePath -> ImportLocation mkImportLocation = mkExportLocation -fromImportLocation :: ImportLocation -> FilePath+fromImportLocation :: ImportLocation -> RawFilePath fromImportLocation = fromExportLocation  {- An identifier for content stored on a remote that has been imported into
Types/Key.hs view
@@ -36,6 +36,7 @@ import Data.ByteString.Builder.Extra import qualified Data.Attoparsec.ByteString as A import qualified Data.Attoparsec.ByteString.Char8 as A8+import Utility.FileSystemEncoding import Data.List import System.Posix.Types import Foreign.C.Types@@ -200,7 +201,7 @@ splitKeyNameExtension' keyname = S8.span (/= '.') keyname  {- A filename may be associated with a Key. -}-newtype AssociatedFile = AssociatedFile (Maybe FilePath)+newtype AssociatedFile = AssociatedFile (Maybe RawFilePath) 	deriving (Show, Eq, Ord)  {- There are several different varieties of keys. -}
Types/Transfer.hs view
@@ -15,6 +15,7 @@ import Utility.PID import Utility.QuickCheck import Utility.Url+import Utility.FileSystemEncoding  import Data.Time.Clock.POSIX import Control.Concurrent@@ -71,9 +72,8 @@ 		<*> pure Nothing -- cannot generate a ThreadID 		<*> pure Nothing -- remote not needed 		<*> arbitrary-		-- associated file cannot be empty (but can be Nothing)-		<*> (AssociatedFile <$> arbitrary `suchThat` (/= Just "")) 		<*> arbitrary+		<*> arbitrary  class Observable a where 	observeBool :: a -> Bool@@ -101,7 +101,7 @@ 	descTransfrerrable :: t -> Maybe String  instance Transferrable AssociatedFile where-	descTransfrerrable (AssociatedFile af) = af+	descTransfrerrable (AssociatedFile af) = fromRawFilePath <$> af  instance Transferrable URLString where 	descTransfrerrable = Just
Types/UUID.hs view
@@ -17,6 +17,7 @@ import Data.ByteString.Builder import qualified Data.Semigroup as Sem +import Git.Types (ConfigValue(..)) import Utility.FileSystemEncoding import Utility.QuickCheck import qualified Utility.SimpleProtocol as Proto@@ -51,6 +52,12 @@  instance ToUUID String where 	toUUID s = toUUID (encodeBS' s)++instance FromUUID ConfigValue where+	fromUUID s = (ConfigValue (fromUUID s))++instance ToUUID ConfigValue where+	toUUID (ConfigValue v) = toUUID v  -- There is no matching FromUUID U.UUID because a git-annex UUID may -- be NoUUID or perhaps contain something not allowed in a canonical UUID.
Upgrade.hs view
@@ -48,7 +48,7 @@   where 	err msg = do 		g <- Annex.gitRepo-		p <- liftIO $ absPath $ Git.repoPath g+		p <- liftIO $ absPath $ fromRawFilePath $ Git.repoPath g 		return $ Just $ unwords 			[ "Repository", p 			, "is at unsupported version"@@ -85,4 +85,3 @@ 	up (RepoVersion 5) = Upgrade.V5.upgrade automatic 	up (RepoVersion 6) = Upgrade.V6.upgrade automatic 	up _ = return True-
Upgrade/V0.hs view
@@ -16,7 +16,7 @@ 	showAction "v0 to v1"  	-- do the reorganisation of the key files-	olddir <- fromRepo gitAnnexDir+	olddir <- fromRawFilePath <$> fromRepo gitAnnexDir 	keys <- getKeysPresent0 olddir 	forM_ keys $ \k -> moveAnnex k $ olddir </> keyFile0 k 
Upgrade/V1.hs view
@@ -85,7 +85,7 @@ 	showAction "updating symlinks" 	top <- fromRepo Git.repoPath 	(files, cleanup) <- inRepo $ LsFiles.inRepo [top]-	forM_ files fixlink+	forM_ files (fixlink . fromRawFilePath) 	void $ liftIO cleanup   where 	fixlink f = do@@ -236,12 +236,13 @@ logFile2 :: Key -> Git.Repo -> String logFile2 = logFile' (hashDirLower def) -logFile' :: (Key -> FilePath) -> Key -> Git.Repo -> String+logFile' :: (Key -> RawFilePath) -> Key -> Git.Repo -> String logFile' hasher key repo =-	gitStateDir repo ++ hasher key ++ keyFile key ++ ".log"+	gitStateDir repo ++ fromRawFilePath (hasher key) ++ fromRawFilePath (keyFile key) ++ ".log"  stateDir :: FilePath stateDir = addTrailingPathSeparator ".git-annex"  gitStateDir :: Git.Repo -> FilePath-gitStateDir repo = addTrailingPathSeparator $ Git.repoPath repo </> stateDir+gitStateDir repo = addTrailingPathSeparator $+	fromRawFilePath (Git.repoPath repo) </> stateDir
Upgrade/V2.hs view
@@ -50,7 +50,7 @@ 	e <- liftIO $ doesDirectoryExist old 	when e $ do 		config <- Annex.getGitConfig-		mapM_ (\(k, f) -> inject f $ locationLogFile config k) =<< locationLogs+		mapM_ (\(k, f) -> inject f $ fromRawFilePath $ locationLogFile config k) =<< locationLogs 		mapM_ (\f -> inject f f) =<< logFiles old  	saveState False@@ -76,13 +76,13 @@   where 	tryDirContents d = catchDefaultIO [] $ dirContents d 	islogfile f = maybe Nothing (\k -> Just (k, f)) $-			locationLogFileKey f+			locationLogFileKey (toRawFilePath f)  inject :: FilePath -> FilePath -> Annex () inject source dest = do 	old <- fromRepo olddir 	new <- liftIO (readFile $ old </> source)-	Annex.Branch.change dest $ \prev -> +	Annex.Branch.change (toRawFilePath dest) $ \prev ->  		encodeBL $ unlines $ nub $ lines (decodeBL prev) ++ lines new  logFiles :: FilePath -> Annex [FilePath]@@ -139,5 +139,7 @@  stateDir :: FilePath stateDir = addTrailingPathSeparator ".git-annex"+ gitStateDir :: Git.Repo -> FilePath-gitStateDir repo = addTrailingPathSeparator $ Git.repoPath repo </> stateDir+gitStateDir repo = addTrailingPathSeparator $+	fromRawFilePath (Git.repoPath repo) </> stateDir
Upgrade/V5.hs view
@@ -5,6 +5,8 @@  - Licensed under the GNU AGPL version 3 or higher.  -} +{-# LANGUAGE OverloadedStrings #-}+ module Upgrade.V5 where  import Annex.Common@@ -119,8 +121,8 @@ 			Just k -> do 				stagePointerFile f Nothing =<< hashPointerFile k 				ifM (isJust <$> getAnnexLinkTarget f)-					( writepointer f k-					, fromdirect f k+					( writepointer (fromRawFilePath f) k+					, fromdirect (fromRawFilePath f) k 					) 				Database.Keys.addAssociatedFile k 					=<< inRepo (toTopFilePath f)@@ -133,7 +135,7 @@ 			-- 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)+			ic <- withTSDelta (liftIO . genInodeCache (toRawFilePath f)) 			void $ Content.linkToAnnex k f ic 		, unlessM (Content.inAnnex k) $ do 			-- Worktree file was deleted or modified;
Upgrade/V5/Direct.hs view
@@ -7,6 +7,8 @@  - Licensed under the GNU AGPL version 3 or higher.  -} +{-# LANGUAGE OverloadedStrings #-}+ module Upgrade.V5.Direct ( 	switchHEADBack, 	setIndirect,@@ -44,12 +46,12 @@ 		-- unset it when enabling direct mode, caching in 		-- core.indirect-worktree 		moveconfig indirectworktree coreworktree-		setConfig (ConfigKey Git.Config.coreBare) val+		setConfig Git.Config.coreBare val 	moveconfig src dest = getConfigMaybe src >>= \case 		Nothing -> noop 		Just wt -> do 			unsetConfig src-			setConfig dest wt+			setConfig dest (fromConfigValue wt) 			reloadConfig  {- Converts a directBranch back to the original branch.@@ -79,7 +81,7 @@ associatedFiles :: Key -> Annex [FilePath] associatedFiles key = do 	files <- associatedFilesRelative key-	top <- fromRepo Git.repoPath+	top <- fromRawFilePath <$> fromRepo Git.repoPath 	return $ map (top </>) files  {- List of files in the tree that are associated with a key, relative to@@ -105,7 +107,9 @@  - expected mtime and inode.  -} goodContent :: Key -> FilePath -> Annex Bool-goodContent key file = sameInodeCache file =<< recordedInodeCache key+goodContent key file =+	sameInodeCache (toRawFilePath file)+		=<< recordedInodeCache key  {- Gets the recorded inode cache for a key.   -
+ Utility/Attoparsec.hs view
@@ -0,0 +1,21 @@+{- attoparsec utility functions+ -+ - Copyright 2019 Joey Hess <id@joeyh.name>+ - Copyright 2007-2015 Bryan O'Sullivan+ -+ - License: BSD-3-clause+ -}++module Utility.Attoparsec where++import qualified Data.Attoparsec.ByteString as A+import qualified Data.ByteString as B++-- | Parse and decode an unsigned octal number.+--+-- This parser does not accept a leading @\"0o\"@ string.+octal :: Integral a => A.Parser a+octal = B.foldl' step 0 `fmap` A.takeWhile1 isOctDigit+  where+	isOctDigit w = w >= 48 && w <= 55+	step a w = a * 8 + fromIntegral (w - 48)
Utility/FileSize.hs view
@@ -33,7 +33,10 @@ getFileSize f = bracket (openFile f ReadMode) hClose hFileSize #endif -{- Gets the size of the file, when its FileStatus is already known. -}+{- Gets the size of the file, when its FileStatus is already known.+ -+ - On windows, uses getFileSize. Otherwise, the FileStatus contains the+ - size, so this does not do any work. -} getFileSize' :: FilePath -> FileStatus -> IO FileSize #ifndef mingw32_HOST_OS getFileSize' _ s = return $ fromIntegral $ fileSize s
Utility/FileSystemEncoding.hs view
@@ -23,10 +23,6 @@ 	encodeBL', 	decodeBS', 	encodeBS',-	decodeW8,-	encodeW8,-	encodeW8NUL,-	decodeW8NUL, 	truncateFilePath, 	s2w8, 	w82s,@@ -148,16 +144,32 @@ {- Faster version that assumes the string does not contain NUL;  - if it does it will be truncated before the NUL. -} decodeBS' :: S.ByteString -> FilePath+#ifndef mingw32_HOST_OS decodeBS' = encodeW8 . S.unpack+#else+decodeBS' = S8.toString+#endif  encodeBS' :: FilePath -> S.ByteString+#ifndef mingw32_HOST_OS encodeBS' = S.pack . decodeW8+#else+encodeBS' = S8.fromString+#endif  decodeBL' :: L.ByteString -> FilePath+#ifndef mingw32_HOST_OS decodeBL' = encodeW8 . L.unpack+#else+decodeBL' = L8.toString+#endif  encodeBL' :: FilePath -> L.ByteString+#ifndef mingw32_HOST_OS encodeBL' = L.pack . decodeW8+#else+encodeBL' = L8.fromString+#endif  {- Recent versions of the unix package have this alias; defined here  - for backwards compatibility. -}
Utility/Format.hs view
@@ -15,7 +15,7 @@ ) where  import Text.Printf (printf)-import Data.Char (isAlphaNum, isOctDigit, isHexDigit, isSpace, chr, ord)+import Data.Char (isAlphaNum, isOctDigit, isHexDigit, isSpace, chr, ord, isAscii) import Data.Maybe (fromMaybe) import Data.Word (Word8) import Data.List (isPrefixOf)@@ -176,12 +176,12 @@ {- For quickcheck.   -  - Encoding and then decoding roundtrips only when- - the string does not contain high unicode, because eg, - - both "\12345" and "\227\128\185" are encoded to "\343\200\271".+ - the string is ascii because eg, both "\12345" and+ - "\227\128\185" are encoded to "\343\200\271".  -- - This property papers over the problem, by only testing chars < 256.+ - This property papers over the problem, by only testing ascii.  -} prop_encode_c_decode_c_roundtrip :: String -> Bool prop_encode_c_decode_c_roundtrip s = s' == decode_c (encode_c s')   where-	s' = filter (\c -> ord c < 256) s+	s' = filter isAscii s
Utility/InodeCache.hs view
@@ -43,6 +43,7 @@ import Common import Utility.TimeStamp import Utility.QuickCheck+import qualified Utility.RawFilePath as R  import System.PosixCompat.Types import Data.Time.Clock.POSIX@@ -180,9 +181,9 @@ 		return $ InodeCache $ InodeCachePrim i sz (MTimeHighRes t) 	_ -> Nothing -genInodeCache :: FilePath -> TSDelta -> IO (Maybe InodeCache)+genInodeCache :: RawFilePath -> TSDelta -> IO (Maybe InodeCache) genInodeCache f delta = catchDefaultIO Nothing $-	toInodeCache delta f =<< getFileStatus f+	toInodeCache delta (fromRawFilePath f) =<< R.getFileStatus f  toInodeCache :: TSDelta -> FilePath -> FileStatus -> IO (Maybe InodeCache) toInodeCache (TSDelta getdelta) f s@@ -202,8 +203,8 @@  - Its InodeCache at the time of its creation is written to the cache file,  - so changes can later be detected. -} data SentinalFile = SentinalFile-	{ sentinalFile :: FilePath-	, sentinalCacheFile :: FilePath+	{ sentinalFile :: RawFilePath+	, sentinalCacheFile :: RawFilePath 	} 	deriving (Show) @@ -220,8 +221,8 @@  writeSentinalFile :: SentinalFile -> IO () writeSentinalFile s = do-	writeFile (sentinalFile s) ""-	maybe noop (writeFile (sentinalCacheFile s) . showInodeCache)+	writeFile (fromRawFilePath (sentinalFile s)) ""+	maybe noop (writeFile (fromRawFilePath (sentinalCacheFile s)) . showInodeCache) 		=<< genInodeCache (sentinalFile s) noTSDelta  data SentinalStatus = SentinalStatus@@ -250,7 +251,7 @@ 				Just new -> return $ calc old new   where 	loadoldcache = catchDefaultIO Nothing $-		readInodeCache <$> readFile (sentinalCacheFile s)+		readInodeCache <$> readFile (fromRawFilePath (sentinalCacheFile s)) 	gennewcache = genInodeCache (sentinalFile s) noTSDelta 	calc (InodeCache (InodeCachePrim oldinode oldsize oldmtime)) (InodeCache (InodeCachePrim newinode newsize newmtime)) = 		SentinalStatus (not unchanged) tsdelta@@ -275,7 +276,7 @@ 	dummy = SentinalStatus True noTSDelta  sentinalFileExists :: SentinalFile -> IO Bool-sentinalFileExists s = allM doesFileExist [sentinalCacheFile s, sentinalFile s]+sentinalFileExists s = allM R.doesPathExist [sentinalCacheFile s, sentinalFile s]  instance Arbitrary InodeCache where 	arbitrary =
Utility/MD5.hs view
@@ -8,13 +8,14 @@  import Data.Bits import Data.Word+import Data.Char -display_32bits_as_dir :: Word32 -> String+display_32bits_as_dir :: Word32 -> [Word8] display_32bits_as_dir w = trim $ swap_pairs cs   where 	-- Need 32 characters to use. To avoid inaverdently making 	-- a real word, use letters that appear less frequently.-	chars = ['0'..'9'] ++ "zqjxkmvwgpfZQJXKMVWGPF"+	chars = map (fromIntegral . ord) (['0'..'9'] ++ "zqjxkmvwgpfZQJXKMVWGPF") 	cs = map (\x -> getc $ (shiftR w (6*x)) .&. 31) [0..7] 	getc n = chars !! fromIntegral n 	swap_pairs (x1:x2:xs) = x2:x1:swap_pairs xs
Utility/Metered.hs view
@@ -258,7 +258,7 @@ 				unless (quietMode oh) $ do 					S.hPut stdout b 					hFlush stdout-				let s = encodeW8 (S.unpack b)+				let s = decodeBS b 				let (mbytes, buf') = progressparser (buf++s) 				case mbytes of 					Nothing -> feedprogress prev buf' h
Utility/Misc.hs view
@@ -12,6 +12,7 @@ 	readFileStrict, 	separate, 	firstLine,+	firstLine', 	segment, 	segmentDelim, 	massReplace,@@ -28,6 +29,7 @@ import Data.List import System.Exit import Control.Applicative+import qualified Data.ByteString as S import Prelude  {- A version of hgetContents that is not lazy. Ensures file is @@ -55,6 +57,11 @@ {- Breaks out the first line. -} firstLine :: String -> String firstLine = takeWhile (/= '\n')++firstLine' :: S.ByteString -> S.ByteString+firstLine' = S.takeWhile (/= nl)+  where+	nl = fromIntegral (ord '\n')  {- Splits a list into segments that are delimited by items matching  - a predicate. (The delimiters are not included in the segments.)
Utility/Path.hs view
@@ -43,6 +43,7 @@ import Utility.UserInfo import Utility.Directory import Utility.Split+import Utility.FileSystemEncoding  {- Simplifies a path, removing any "." component, collapsing "dir/..",   - and removing the trailing path separator.@@ -112,7 +113,10 @@  - are all equivilant.  -} dirContains :: FilePath -> FilePath -> Bool-dirContains a b = a == b || a' == b' || (addTrailingPathSeparator a') `isPrefixOf` b'+dirContains a b = a == b+	|| a' == b'+	|| (addTrailingPathSeparator a') `isPrefixOf` b'+	|| a' == "." && normalise ("." </> b') == b'   where 	a' = norm a 	b' = norm b@@ -200,20 +204,21 @@  - we stop preserving ordering at that point. Presumably a user passing  - that many paths in doesn't care too much about order of the later ones.  -}-segmentPaths :: [FilePath] -> [FilePath] -> [[FilePath]]+segmentPaths :: [RawFilePath] -> [RawFilePath] -> [[RawFilePath]] segmentPaths [] new = [new] segmentPaths [_] new = [new] -- optimisation segmentPaths (l:ls) new = found : segmentPaths ls rest   where 	(found, rest) = if length ls < 100-		then partition (l `dirContains`) new-		else break (\p -> not (l `dirContains` p)) new+		then partition inl new+		else break (not . inl) new+	inl f = fromRawFilePath l `dirContains` fromRawFilePath f  {- This assumes that it's cheaper to call segmentPaths on the result,  - than it would be to run the action separately with each path. In  - the case of git file list commands, that assumption tends to hold.  -}-runSegmentPaths :: ([FilePath] -> IO [FilePath]) -> [FilePath] -> IO [[FilePath]]+runSegmentPaths :: ([RawFilePath] -> IO [RawFilePath]) -> [RawFilePath] -> IO [[RawFilePath]] runSegmentPaths a paths = segmentPaths paths <$> a paths  {- Converts paths in the home directory to use ~/ -}
Utility/RawFilePath.hs view
@@ -1,5 +1,12 @@ {- Portability shim around System.Posix.Files.ByteString  -+ - On unix, this makes syscalls using RawFilesPaths as efficiently as+ - possible.+ -+ - On Windows, filenames are in unicode, so RawFilePaths have to be+ - decoded. So this library will work, but less efficiently than using+ - FilePath would.+ -  - Copyright 2019 Joey Hess <id@joeyh.name>  -  - License: BSD-2-clause@@ -10,19 +17,33 @@ module Utility.RawFilePath ( 	RawFilePath, 	readSymbolicLink,+	getFileStatus,+	getSymbolicLinkStatus,+	doesPathExist, ) where  #ifndef mingw32_HOST_OS+import Utility.FileSystemEncoding (RawFilePath) import System.Posix.Files.ByteString-import System.Posix.ByteString.FilePath++doesPathExist :: RawFilePath -> IO Bool+doesPathExist = fileExist+ #else import qualified Data.ByteString as B-import System.IO.Error--type RawFilePath = B.ByteString+import qualified System.PosixCompat as P+import qualified System.Directory as D+import Utility.FileSystemEncoding  readSymbolicLink :: RawFilePath -> IO RawFilePath-readSymbolicLink _ = ioError $ mkIOError illegalOperationErrorType x Nothing Nothing-  where-	x = "Utility.RawFilePath.readSymbolicLink: not supported"+readSymbolicLink f = toRawFilePath <$> P.readSymbolicLink (fromRawFilePath f)++getFileStatus :: RawFilePath -> IO FileStatus+getFileStatus = P.getFileStatus . fromRawFilePath++getSymbolicLinkStatus :: RawFilePath -> IO FileStatus+getSymbolicLinkStatus = P.getSymbolicLinkStatus . fromRawFilePath++doesPathExist :: RawFilePath -> IO Bool+doesPathExist = D.doesPathExist . fromRawFilePath #endif
Utility/Split.hs view
@@ -34,6 +34,6 @@ replace :: Eq a => [a] -> [a] -> [a] -> [a]  replace old new = intercalate new . split old --- | Only traverses the list once while dropping the last n characters.+-- | Only traverses the list once while dropping the last n items. dropFromEnd :: Int -> [a] -> [a] dropFromEnd n l = zipWith const l (drop n l)
doc/git-annex-matchexpression.mdwn view
@@ -59,6 +59,8 @@  [[git-annex-preferred-content]](1) +[[git-annex-matching-expression]](1)+ # AUTHOR  Joey Hess <id@joeyh.name>
doc/git-annex.mdwn view
@@ -891,9 +891,13 @@    Used to configure which files are large enough to be added to the annex.   It is an expression that matches the large files, eg-  "*.mp3 or largerthan(500kb)"+  "include=*.mp3 or largerthan(500kb)"+  See [[git-annex-matching-expression]](1) for details on the syntax.    Overrides any annex.largefiles attributes in `.gitattributes` files.+  +  To configure a default annex.largefiles for all clones of the repository,+  this can be set in [[git-annex-config]](1).    This configures the behavior of both git-annex and git when adding   files to the repository. By default, `git-annex add` adds all files@@ -906,13 +910,10 @@   `git annex import`, `git annex addurl`, `git annex importfeed`   and the assistant. -  See <https://git-annex.branchable.com/tips/largefiles> for syntax-  documentation and more.- * `annex.gitaddtoannex` -  Setting this to false will prevent `git add` from honoring the -  annex.largefiles configuration.+  Setting this to false will prevent `git add` from adding+  files to the annex, despite the annex.largefiles configuration.  * `annex.addsmallfiles` @@ -922,15 +923,23 @@  * `annex.addunlocked` -  Set to true to make commands like `git-annex add` that add files to the-  repository add them in unlocked form. The default is for these commands-  to add files in locked form. +  Commands like `git-annex add` default to adding files to the repository+  in locked form. This can make them add the files in unlocked form,+  the same as if [[git-annex-unlock]](1) were run on the files.++  This can be set to "true" to add everything unlocked, or it can be a more+  complicated expression that matches files by name, size, or content. See+  [[git-annex-matching-expression]](1) for details.   +  To configure a default annex.addunlocked for all clones of the repository,+  this can be set in [[git-annex-config]](1).+     (Using `git add` always adds files in unlocked form and it is not   affected by this setting.)--  When a repository has core.symlinks set to false, it implicitly-  sets annex.addunlocked to true.+  +  When a repository has core.symlinks set to false, or has an adjusted +  unlocked branch checked out, this setting is ignored, and files are +  always added to the repository in unlocked form.  * `annex.numcopies` @@ -1695,9 +1704,11 @@ 	*.ogg annex.backend=SHA256E  There is a annex.largefiles attribute, which is used to configure which-files are large enough to be added to the annex.-See the documentation above of the annex.largefiles git config-and <https://git-annex.branchable.com/tips/largefiles> for details.+files are large enough to be added to the annex. Since attributes cannot+contain spaces, it is difficult to use for more complex annex.largefiles+settings. Setting annex.largefiles in [[git-annex-config]](1) is an easier+way to configure it across all clones of the repository.+See [[git-annex-matching-expression]](1) for details on the syntax.  The numcopies setting can also be configured on a per-file-type basis via the `annex.numcopies` attribute in `.gitattributes` files. This overrides
git-annex.cabal view
@@ -1,5 +1,5 @@ Name: git-annex-Version: 7.20191218+Version: 7.20191230 Cabal-Version: >= 1.8 License: AGPL-3 Maintainer: Joey Hess <id@joeyh.name>@@ -296,6 +296,7 @@ custom-setup   Setup-Depends: base (>= 4.11.1.0), hslogger, split, unix-compat, process,     filepath, exceptions, bytestring, directory, IfElse, data-default,+    filepath-bytestring (>= 1.4.2.1.0),     utf8-string, transformers, Cabal  Executable git-annex@@ -320,6 +321,7 @@    directory (>= 1.2),    disk-free-space,    filepath,+   filepath-bytestring (>= 1.4.2.1.0),    IfElse,    hslogger,    monad-logger,@@ -1020,6 +1022,7 @@     Utility.Aeson     Utility.Android     Utility.Applicative+    Utility.Attoparsec     Utility.AuthToken     Utility.Base64     Utility.Batch
stack.yaml view
@@ -24,6 +24,7 @@ - sandi-0.5 - http-client-0.5.14 - silently-1.2.5.1+- filepath-bytestring-1.4.2.1.1 explicit-setup-deps:   git-annex: true resolver: lts-13.29