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 +2/−2
- Annex/AdjustedBranch.hs +4/−4
- Annex/AutoMerge.hs +15/−13
- Annex/Branch.hs +15/−15
- Annex/Branch/Transitions.hs +1/−1
- Annex/CatFile.hs +22/−19
- Annex/ChangedRefs.hs +1/−1
- Annex/Content.hs +40/−29
- Annex/Content/LowLevel.hs +1/−1
- Annex/Content/PointerFile.hs +17/−14
- Annex/Difference.hs +1/−1
- Annex/DirHashes.hs +21/−11
- Annex/Drop.hs +4/−3
- Annex/Environment.hs +4/−2
- Annex/FileMatcher.hs +55/−18
- Annex/Fixup.hs +19/−13
- Annex/GitOverlay.hs +3/−2
- Annex/HashObject.hs +1/−1
- Annex/Import.hs +10/−9
- Annex/Ingest.hs +44/−22
- Annex/Init.hs +8/−4
- Annex/InodeSentinal.hs +2/−2
- Annex/Journal.hs +31/−14
- Annex/Link.hs +31/−31
- Annex/Locations.hs +121/−87
- Annex/MetaData.hs +3/−3
- Annex/Notification.hs +1/−1
- Annex/NumCopies.hs +1/−1
- Annex/Perms.hs +1/−1
- Annex/SpecialRemote.hs +3/−1
- Annex/Ssh.hs +2/−1
- Annex/UUID.hs +11/−11
- Annex/VariantFile.hs +1/−1
- Annex/Version.hs +2/−0
- Annex/View.hs +8/−5
- Annex/WorkTree.hs +14/−11
- Assistant/MakeRemote.hs +2/−0
- Assistant/MakeRepo.hs +2/−0
- Assistant/Repair.hs +2/−2
- Assistant/Sync.hs +2/−0
- Assistant/Threads/Committer.hs +5/−5
- Assistant/Threads/ConfigMonitor.hs +5/−4
- Assistant/Threads/Merger.hs +1/−1
- Assistant/Threads/MountWatcher.hs +1/−1
- Assistant/Threads/PairListener.hs +1/−1
- Assistant/Threads/SanityChecker.hs +4/−3
- Assistant/Threads/Watcher.hs +20/−17
- Assistant/Threads/WebApp.hs +1/−1
- Assistant/TransferSlots.hs +1/−1
- Assistant/Unused.hs +1/−1
- Assistant/Upgrade.hs +2/−2
- Assistant/WebApp/Configurators/Delete.hs +1/−1
- Assistant/WebApp/Configurators/Edit.hs +4/−3
- Assistant/WebApp/Configurators/Local.hs +1/−1
- Assistant/WebApp/Configurators/Pairing.hs +1/−1
- Assistant/WebApp/Configurators/Preferences.hs +2/−2
- Assistant/WebApp/Configurators/Ssh.hs +3/−2
- Assistant/WebApp/DashBoard.hs +3/−2
- Backend/Hash.hs +1/−1
- Backend/Utilities.hs +4/−2
- Backend/WORM.hs +2/−1
- CHANGELOG +28/−0
- COPYRIGHT +34/−1
- CmdLine/Batch.hs +2/−1
- CmdLine/GitAnnex/Options.hs +1/−1
- CmdLine/GitAnnexShell/Fields.hs +1/−1
- CmdLine/Seek.hs +24/−22
- Command/Add.hs +22/−19
- Command/AddUnused.hs +1/−1
- Command/AddUrl.hs +56/−56
- Command/Config.hs +25/−14
- Command/ConfigList.hs +5/−3
- Command/ContentLocation.hs +5/−2
- Command/Copy.hs +3/−3
- Command/DiffDriver.hs +4/−3
- Command/Drop.hs +2/−2
- Command/EnableRemote.hs +2/−0
- Command/ExamineKey.hs +1/−1
- Command/Export.hs +9/−10
- Command/Find.hs +9/−7
- Command/Fix.hs +18/−15
- Command/FromKey.hs +3/−3
- Command/Fsck.hs +33/−32
- Command/FuzzTest.hs +6/−5
- Command/Get.hs +3/−3
- Command/Import.hs +14/−9
- Command/ImportFeed.hs +18/−16
- Command/Info.hs +9/−9
- Command/InitRemote.hs +2/−0
- Command/Inprogress.hs +1/−1
- Command/List.hs +3/−3
- Command/Lock.hs +17/−15
- Command/Log.hs +6/−6
- Command/LookupKey.hs +4/−3
- Command/Map.hs +6/−3
- Command/MatchExpression.hs +1/−2
- Command/MetaData.hs +5/−5
- Command/Migrate.hs +6/−6
- Command/Mirror.hs +2/−2
- Command/Move.hs +2/−2
- Command/Multicast.hs +2/−1
- Command/P2P.hs +2/−0
- Command/PostReceive.hs +2/−0
- Command/PreCommit.hs +2/−2
- Command/ReKey.hs +17/−16
- Command/Reinject.hs +2/−2
- Command/ResolveMerge.hs +1/−1
- Command/RmUrl.hs +4/−2
- Command/SendKey.hs +2/−1
- Command/Smudge.hs +48/−16
- Command/Status.hs +1/−1
- Command/Sync.hs +4/−3
- Command/TestRemote.hs +6/−6
- Command/TransferInfo.hs +2/−1
- Command/TransferKeys.hs +2/−2
- Command/Unannex.hs +9/−8
- Command/Undo.hs +5/−4
- Command/Uninit.hs +6/−5
- Command/Unlock.hs +7/−6
- Command/Unused.hs +5/−4
- Command/Vicfg.hs +5/−4
- Command/View.hs +4/−3
- Command/WebApp.hs +3/−1
- Command/Whereis.hs +2/−2
- Config.hs +15/−13
- Config/GitConfig.hs +23/−19
- Config/Smudge.hs +3/−0
- Database/Export.hs +10/−10
- Database/Keys.hs +12/−8
- Database/Keys/SQL.hs +6/−5
- Git.hs +20/−19
- Git/AutoCorrect.hs +3/−1
- Git/Branch.hs +14/−10
- Git/CatFile.hs +15/−13
- Git/Command.hs +25/−15
- Git/Config.hs +60/−41
- Git/ConfigTypes.hs +23/−15
- Git/Construct.hs +9/−9
- Git/CurrentRepo.hs +9/−4
- Git/DiffTree.hs +4/−4
- Git/Env.hs +4/−2
- Git/FilePath.hs +25/−20
- Git/Filename.hs +36/−15
- Git/GCrypt.hs +14/−9
- Git/HashObject.hs +7/−7
- Git/Hook.hs +1/−1
- Git/Index.hs +1/−1
- Git/LsFiles.hs +55/−52
- Git/LsTree.hs +30/−20
- Git/Objects.hs +1/−1
- Git/Ref.hs +18/−12
- Git/RefLog.hs +1/−1
- Git/Remote.hs +16/−12
- Git/Repair.hs +11/−11
- Git/Status.hs +7/−7
- Git/Tree.hs +9/−9
- Git/Types.hs +48/−15
- Git/UnionMerge.hs +4/−3
- Git/UpdateIndex.hs +23/−18
- Key.hs +7/−0
- Limit.hs +16/−12
- Logs.hs +78/−62
- Logs/Config.hs +23/−19
- Logs/Export.hs +9/−4
- Logs/Location.hs +1/−1
- Logs/MetaData.hs +4/−4
- Logs/PreferredContent.hs +0/−1
- Logs/PreferredContent/Raw.hs +1/−1
- Logs/Presence.hs +6/−6
- Logs/SingleValue.hs +3/−3
- Logs/Smudge.hs +5/−3
- Logs/Transfer.hs +6/−6
- Logs/Transitions.hs +4/−2
- Messages.hs +18/−14
- Messages/Internal.hs +6/−4
- Messages/JSON.hs +3/−2
- Messages/Progress.hs +1/−0
- P2P/Annex.hs +1/−1
- P2P/IO.hs +1/−1
- P2P/Protocol.hs +4/−3
- Remote.hs +6/−4
- Remote/Adb.hs +3/−3
- Remote/BitTorrent.hs +2/−2
- Remote/Bup.hs +8/−6
- Remote/Directory.hs +10/−8
- Remote/Directory/LegacyChunked.hs +1/−1
- Remote/External.hs +8/−5
- Remote/External/Types.hs +4/−4
- Remote/GCrypt.hs +20/−14
- Remote/Git.hs +15/−12
- Remote/GitLFS.hs +6/−4
- Remote/Helper/Chunked/Legacy.hs +1/−1
- Remote/Helper/Git.hs +2/−2
- Remote/Helper/Special.hs +10/−3
- Remote/Helper/Ssh.hs +2/−2
- Remote/Hook.hs +8/−6
- Remote/Rsync.hs +8/−8
- Remote/Rsync/RsyncUrl.hs +7/−6
- Remote/S3.hs +4/−2
- Remote/WebDAV.hs +1/−1
- Remote/WebDAV/DavLocation.hs +10/−7
- Test.hs +6/−5
- Test/Framework.hs +8/−6
- Types/ActionItem.hs +10/−8
- Types/Difference.hs +8/−4
- Types/Distribution.hs +2/−2
- Types/Export.hs +10/−9
- Types/FileMatcher.hs +3/−2
- Types/GitConfig.hs +38/−20
- Types/Import.hs +2/−2
- Types/Key.hs +2/−1
- Types/Transfer.hs +3/−3
- Types/UUID.hs +7/−0
- Upgrade.hs +1/−2
- Upgrade/V0.hs +1/−1
- Upgrade/V1.hs +5/−4
- Upgrade/V2.hs +6/−4
- Upgrade/V5.hs +5/−3
- Upgrade/V5/Direct.hs +8/−4
- Utility/Attoparsec.hs +21/−0
- Utility/FileSize.hs +4/−1
- Utility/FileSystemEncoding.hs +16/−4
- Utility/Format.hs +5/−5
- Utility/InodeCache.hs +9/−8
- Utility/MD5.hs +3/−2
- Utility/Metered.hs +1/−1
- Utility/Misc.hs +7/−0
- Utility/Path.hs +10/−5
- Utility/RawFilePath.hs +28/−7
- Utility/Split.hs +1/−1
- doc/git-annex-matchexpression.mdwn +2/−0
- doc/git-annex.mdwn +26/−15
- git-annex.cabal +4/−1
- stack.yaml +1/−0
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
COPYRIGHT view
@@ -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