Merge branch 'bytestring-ref'

This commit is contained in:
Joey Hess 2020-04-08 14:10:24 -04:00
commit 89c3b20695
No known key found for this signature in database
GPG key ID: DB12DB0FF05F8F38
55 changed files with 329 additions and 226 deletions

View file

@ -5,7 +5,7 @@
- Licensed under the GNU AGPL version 3 or higher. - Licensed under the GNU AGPL version 3 or higher.
-} -}
{-# LANGUAGE BangPatterns #-} {-# LANGUAGE BangPatterns, OverloadedStrings #-}
module Annex.AdjustedBranch ( module Annex.AdjustedBranch (
Adjustment(..), Adjustment(..),
@ -61,6 +61,7 @@ import qualified Database.Keys
import Config import Config
import qualified Data.Map as M import qualified Data.Map as M
import qualified Data.ByteString as S
-- How to perform various adjustments to a TreeItem. -- How to perform various adjustments to a TreeItem.
class AdjustTreeItem t where class AdjustTreeItem t where
@ -128,7 +129,7 @@ newtype BasisBranch = BasisBranch Ref
-- refs/basis/adjusted/master(unlocked). -- refs/basis/adjusted/master(unlocked).
basisBranch :: AdjBranch -> BasisBranch basisBranch :: AdjBranch -> BasisBranch
basisBranch (AdjBranch adjbranch) = BasisBranch $ basisBranch (AdjBranch adjbranch) = BasisBranch $
Ref ("refs/basis/" ++ fromRef (Git.Ref.base adjbranch)) Ref ("refs/basis/" <> fromRef' (Git.Ref.base adjbranch))
getAdjustment :: Branch -> Maybe Adjustment getAdjustment :: Branch -> Maybe Adjustment
getAdjustment = fmap fst . adjustedToOriginal getAdjustment = fmap fst . adjustedToOriginal
@ -405,7 +406,8 @@ mergeToAdjustedBranch tomerge (origbranch, adj) mergeconfig canresolvemerge comm
<||> (resolveMerge (Just updatedorig) tomerge True <&&> commitResolvedMerge commitmode) <||> (resolveMerge (Just updatedorig) tomerge True <&&> commitResolvedMerge commitmode)
if merged if merged
then do then do
!mergecommit <- liftIO $ extractSha <$> readFile (tmpgit </> "HEAD") !mergecommit <- liftIO $ extractSha
<$> S.readFile (tmpgit </> "HEAD")
-- This is run after the commit lock is dropped. -- This is run after the commit lock is dropped.
return $ postmerge mergecommit return $ postmerge mergecommit
else return $ return False else return $ return False

View file

@ -5,6 +5,8 @@
- Licensed under the GNU AGPL version 3 or higher. - Licensed under the GNU AGPL version 3 or higher.
-} -}
{-# LANGUAGE OverloadedStrings #-}
module Annex.AdjustedBranch.Name ( module Annex.AdjustedBranch.Name (
originalToAdjusted, originalToAdjusted,
adjustedToOriginal, adjustedToOriginal,
@ -18,14 +20,15 @@ import qualified Git.Ref
import Utility.Misc import Utility.Misc
import Control.Applicative import Control.Applicative
import Data.List import Data.Char
import qualified Data.ByteString as S
adjustedBranchPrefix :: String adjustedBranchPrefix :: S.ByteString
adjustedBranchPrefix = "refs/heads/adjusted/" adjustedBranchPrefix = "refs/heads/adjusted/"
class SerializeAdjustment t where class SerializeAdjustment t where
serializeAdjustment :: t -> String serializeAdjustment :: t -> S.ByteString
deserializeAdjustment :: String -> Maybe t deserializeAdjustment :: S.ByteString -> Maybe t
instance SerializeAdjustment Adjustment where instance SerializeAdjustment Adjustment where
serializeAdjustment (LinkAdjustment l) = serializeAdjustment (LinkAdjustment l) =
@ -33,7 +36,7 @@ instance SerializeAdjustment Adjustment where
serializeAdjustment (PresenceAdjustment p Nothing) = serializeAdjustment (PresenceAdjustment p Nothing) =
serializeAdjustment p serializeAdjustment p
serializeAdjustment (PresenceAdjustment p (Just l)) = serializeAdjustment (PresenceAdjustment p (Just l)) =
serializeAdjustment p ++ "-" ++ serializeAdjustment l serializeAdjustment p <> "-" <> serializeAdjustment l
deserializeAdjustment s = deserializeAdjustment s =
(LinkAdjustment <$> deserializeAdjustment s) (LinkAdjustment <$> deserializeAdjustment s)
<|> <|>
@ -41,7 +44,7 @@ instance SerializeAdjustment Adjustment where
<|> <|>
(PresenceAdjustment <$> deserializeAdjustment s <*> pure Nothing) (PresenceAdjustment <$> deserializeAdjustment s <*> pure Nothing)
where where
(s1, s2) = separate (== '-') s (s1, s2) = separate' (== (fromIntegral (ord '-'))) s
instance SerializeAdjustment LinkAdjustment where instance SerializeAdjustment LinkAdjustment where
serializeAdjustment UnlockAdjustment = "unlocked" serializeAdjustment UnlockAdjustment = "unlocked"
@ -65,19 +68,21 @@ newtype AdjBranch = AdjBranch { adjBranch :: Branch }
originalToAdjusted :: OrigBranch -> Adjustment -> AdjBranch originalToAdjusted :: OrigBranch -> Adjustment -> AdjBranch
originalToAdjusted orig adj = AdjBranch $ Ref $ originalToAdjusted orig adj = AdjBranch $ Ref $
adjustedBranchPrefix ++ base ++ '(' : serializeAdjustment adj ++ ")" adjustedBranchPrefix <> base <> "(" <> serializeAdjustment adj <> ")"
where where
base = fromRef (Git.Ref.base orig) base = fromRef' (Git.Ref.base orig)
type OrigBranch = Branch type OrigBranch = Branch
adjustedToOriginal :: Branch -> Maybe (Adjustment, OrigBranch) adjustedToOriginal :: Branch -> Maybe (Adjustment, OrigBranch)
adjustedToOriginal b adjustedToOriginal b
| adjustedBranchPrefix `isPrefixOf` bs = do | adjustedBranchPrefix `S.isPrefixOf` bs = do
let (base, as) = separate (== '(') (drop prefixlen bs) let (base, as) = separate' (== openparen) (S.drop prefixlen bs)
adj <- deserializeAdjustment (takeWhile (/= ')') as) adj <- deserializeAdjustment (S.takeWhile (/= closeparen) as)
Just (adj, Git.Ref.branchRef (Ref base)) Just (adj, Git.Ref.branchRef (Ref base))
| otherwise = Nothing | otherwise = Nothing
where where
bs = fromRef b bs = fromRef' b
prefixlen = length adjustedBranchPrefix prefixlen = S.length adjustedBranchPrefix
openparen = fromIntegral (ord '(')
closeparen = fromIntegral (ord ')')

View file

@ -5,6 +5,8 @@
- Licensed under the GNU AGPL version 3 or higher. - Licensed under the GNU AGPL version 3 or higher.
-} -}
{-# LANGUAGE OverloadedStrings #-}
module Annex.Branch ( module Annex.Branch (
fullname, fullname,
name, name,
@ -29,7 +31,9 @@ module Annex.Branch (
withIndex, withIndex,
) where ) where
import qualified Data.ByteString as B
import qualified Data.ByteString.Lazy as L import qualified Data.ByteString.Lazy as L
import qualified Data.ByteString.Char8 as B8
import qualified Data.Set as S import qualified Data.Set as S
import qualified Data.Map as M import qualified Data.Map as M
import Data.Function import Data.Function
@ -55,7 +59,7 @@ import qualified Git.LsTree
import Git.LsTree (lsTreeParams) import Git.LsTree (lsTreeParams)
import qualified Git.HashObject import qualified Git.HashObject
import Annex.HashObject import Annex.HashObject
import Git.Types (Ref(..), fromRef, RefDate, TreeItemType(..)) import Git.Types (Ref(..), fromRef, fromRef', RefDate, TreeItemType(..))
import Git.FilePath import Git.FilePath
import Annex.CatFile import Annex.CatFile
import Annex.Perms import Annex.Perms
@ -77,11 +81,11 @@ name = Git.Ref "git-annex"
{- Fully qualified name of the branch. -} {- Fully qualified name of the branch. -}
fullname :: Git.Ref fullname :: Git.Ref
fullname = Git.Ref $ "refs/heads/" ++ fromRef name fullname = Git.Ref $ "refs/heads/" <> fromRef' name
{- Branch's name in origin. -} {- Branch's name in origin. -}
originname :: Git.Ref originname :: Git.Ref
originname = Git.Ref $ "origin/" ++ fromRef name originname = Git.Ref $ "origin/" <> fromRef' name
{- Does origin/git-annex exist? -} {- Does origin/git-annex exist? -}
hasOrigin :: Annex Bool hasOrigin :: Annex Bool
@ -327,9 +331,9 @@ commitIndex' jl branchref message basemessage retrynum parents = do
where where
-- look for "parent ref" lines and return the refs -- look for "parent ref" lines and return the refs
commitparents = map (Git.Ref . snd) . filter isparent . commitparents = map (Git.Ref . snd) . filter isparent .
map (toassoc . decodeBL) . L.split newline map (toassoc . L.toStrict) . L.split newline
newline = fromIntegral (ord '\n') newline = fromIntegral (ord '\n')
toassoc = separate (== ' ') toassoc = separate' (== (fromIntegral (ord ' ')))
isparent (k,_) = k == "parent" isparent (k,_) = k == "parent"
{- The race can be detected by checking the commit's {- The race can be detected by checking the commit's
@ -438,8 +442,8 @@ forceUpdateIndex jl branchref = do
needUpdateIndex :: Git.Ref -> Annex Bool needUpdateIndex :: Git.Ref -> Annex Bool
needUpdateIndex branchref = do needUpdateIndex branchref = do
f <- fromRepo gitAnnexIndexStatus f <- fromRepo gitAnnexIndexStatus
committedref <- Git.Ref . firstLine <$> committedref <- Git.Ref . firstLine' <$>
liftIO (catchDefaultIO "" $ readFileStrict f) liftIO (catchDefaultIO mempty $ B.readFile f)
return (committedref /= branchref) return (committedref /= branchref)
{- Record that the branch's index has been updated to correspond to a {- Record that the branch's index has been updated to correspond to a
@ -621,11 +625,12 @@ ignoreRefs rs = do
unlines $ map fromRef $ S.elems s unlines $ map fromRef $ S.elems s
getIgnoredRefs :: Annex (S.Set Git.Sha) getIgnoredRefs :: Annex (S.Set Git.Sha)
getIgnoredRefs = S.fromList . mapMaybe Git.Sha.extractSha . lines <$> content getIgnoredRefs =
S.fromList . mapMaybe Git.Sha.extractSha . B8.lines <$> content
where where
content = do content = do
f <- fromRepo gitAnnexIgnoredRefs f <- fromRepo gitAnnexIgnoredRefs
liftIO $ catchDefaultIO "" $ readFile f liftIO $ catchDefaultIO mempty $ B.readFile f
addMergedRefs :: [(Git.Sha, Git.Branch)] -> Annex () addMergedRefs :: [(Git.Sha, Git.Branch)] -> Annex ()
addMergedRefs [] = return () addMergedRefs [] = return ()
@ -643,11 +648,11 @@ getMergedRefs = S.fromList . map fst <$> getMergedRefs'
getMergedRefs' :: Annex [(Git.Sha, Git.Branch)] getMergedRefs' :: Annex [(Git.Sha, Git.Branch)]
getMergedRefs' = do getMergedRefs' = do
f <- fromRepo gitAnnexMergedRefs f <- fromRepo gitAnnexMergedRefs
s <- liftIO $ catchDefaultIO "" $ readFile f s <- liftIO $ catchDefaultIO mempty $ B.readFile f
return $ map parse $ lines s return $ map parse $ B8.lines s
where where
parse l = parse l =
let (s, b) = separate (== '\t') l let (s, b) = separate' (== (fromIntegral (ord '\t'))) l
in (Ref s, Ref b) in (Ref s, Ref b)
{- Grafts a treeish into the branch at the specified location, {- Grafts a treeish into the branch at the specified location,

View file

@ -1,6 +1,6 @@
{- Waiting for changed git refs {- Waiting for changed git refs
- -
- Copyright 2014-216 Joey Hess <id@joeyh.name> - Copyright 2014-2016 Joey Hess <id@joeyh.name>
- -
- Licensed under the GNU AGPL version 3 or higher. - Licensed under the GNU AGPL version 3 or higher.
-} -}
@ -24,13 +24,14 @@ import qualified Utility.SimpleProtocol as Proto
import Control.Concurrent import Control.Concurrent
import Control.Concurrent.STM import Control.Concurrent.STM
import Control.Concurrent.STM.TBMChan import Control.Concurrent.STM.TBMChan
import qualified Data.ByteString as S
newtype ChangedRefs = ChangedRefs [Git.Ref] newtype ChangedRefs = ChangedRefs [Git.Ref]
deriving (Show) deriving (Show)
instance Proto.Serializable ChangedRefs where instance Proto.Serializable ChangedRefs where
serialize (ChangedRefs l) = unwords $ map Git.fromRef l serialize (ChangedRefs l) = unwords $ map Git.fromRef l
deserialize = Just . ChangedRefs . map Git.Ref . words deserialize = Just . ChangedRefs . map (Git.Ref . encodeBS) . words
data ChangedRefsHandle = ChangedRefsHandle DirWatcherHandle (TBMChan Git.Sha) data ChangedRefsHandle = ChangedRefsHandle DirWatcherHandle (TBMChan Git.Sha)
@ -97,7 +98,7 @@ notifyHook chan reffile _
| ".lock" `isSuffixOf` reffile = noop | ".lock" `isSuffixOf` reffile = noop
| otherwise = void $ do | otherwise = void $ do
sha <- catchDefaultIO Nothing $ sha <- catchDefaultIO Nothing $
extractSha <$> readFile reffile extractSha <$> S.readFile reffile
-- When the channel is full, there is probably no reader -- When the channel is full, there is probably no reader
-- running, or ref changes have been occuring very fast, -- running, or ref changes have been occuring very fast,
-- so it's ok to not write the change to it. -- so it's ok to not write the change to it.

View file

@ -14,7 +14,6 @@ import Types.Key
import qualified Git import qualified Git
import qualified Types.Remote as Remote import qualified Types.Remote as Remote
import Messages import Messages
import Utility.FileSystemEncoding
import Control.Applicative import Control.Applicative
import Data.Maybe import Data.Maybe
@ -34,7 +33,7 @@ exportKey sha = mk <$> catKey sha
where where
mk (Just k) = AnnexKey k mk (Just k) = AnnexKey k
mk Nothing = GitKey $ mkKey $ \k -> k mk Nothing = GitKey $ mkKey $ \k -> k
{ keyName = encodeBS $ Git.fromRef sha { keyName = Git.fromRef' sha
, keyVariety = SHA1Key (HasExt False) , keyVariety = SHA1Key (HasExt False)
, keySize = Nothing , keySize = Nothing
, keyMtime = Nothing , keyMtime = Nothing

View file

@ -122,7 +122,9 @@ buildImportCommit remote importtreeconfig importcommitconfig importable =
Nothing -> pure committedtree Nothing -> pure committedtree
Just dir -> Just dir ->
let subtreeref = Ref $ let subtreeref = Ref $
fromRef committedtree ++ ":" ++ fromRawFilePath (getTopFilePath dir) fromRef' committedtree
<> ":"
<> getTopFilePath dir
in fromMaybe emptyTree in fromMaybe emptyTree
<$> inRepo (Git.Ref.tree subtreeref) <$> inRepo (Git.Ref.tree subtreeref)
updateexportdb importedtree updateexportdb importedtree

View file

@ -5,6 +5,8 @@
- Licensed under the GNU AGPL version 3 or higher. - Licensed under the GNU AGPL version 3 or higher.
-} -}
{-# LANGUAGE OverloadedStrings #-}
module Annex.TaggedPush where module Annex.TaggedPush where
import Annex.Common import Annex.Common
@ -16,6 +18,8 @@ import qualified Git.Command
import qualified Git.Branch import qualified Git.Branch
import Utility.Base64 import Utility.Base64
import qualified Data.ByteString as S
{- Converts a git branch into a branch that is tagged with a UUID, typically {- Converts a git branch into a branch that is tagged with a UUID, typically
- the UUID of the repo that will be pushing it, and possibly with other - the UUID of the repo that will be pushing it, and possibly with other
- information. - information.
@ -31,11 +35,11 @@ import Utility.Base64
- refs, per git-check-ref-format. - refs, per git-check-ref-format.
-} -}
toTaggedBranch :: UUID -> Maybe String -> Git.Branch -> Git.Ref toTaggedBranch :: UUID -> Maybe String -> Git.Branch -> Git.Ref
toTaggedBranch u info b = Git.Ref $ intercalate "/" $ catMaybes toTaggedBranch u info b = Git.Ref $ S.intercalate "/" $ catMaybes
[ Just "refs/synced" [ Just "refs/synced"
, Just $ fromUUID u , Just $ fromUUID u
, toB64 <$> info , toB64' . encodeBS <$> info
, Just $ Git.fromRef $ Git.Ref.base b , Just $ Git.fromRef' $ Git.Ref.base b
] ]
fromTaggedBranch :: Git.Ref -> Maybe (UUID, Maybe String) fromTaggedBranch :: Git.Ref -> Maybe (UUID, Maybe String)

View file

@ -109,6 +109,6 @@ isAnnexBranch f = n `isSuffixOf` f
n = '/' : Git.fromRef Annex.Branch.name n = '/' : Git.fromRef Annex.Branch.name
fileToBranch :: FilePath -> Git.Ref fileToBranch :: FilePath -> Git.Ref
fileToBranch f = Git.Ref $ "refs" </> base fileToBranch f = Git.Ref $ encodeBS' $ "refs" </> base
where where
base = Prelude.last $ split "/refs/" f base = Prelude.last $ split "/refs/" f

View file

@ -330,7 +330,7 @@ addLink :: FilePath -> FilePath -> Maybe Key -> Assistant (Maybe Change)
addLink file link mk = do addLink file link mk = do
debug ["add symlink", file] debug ["add symlink", file]
liftAnnex $ do liftAnnex $ do
v <- catObjectDetails $ Ref $ ':':file v <- catObjectDetails $ Ref $ encodeBS' $ ':':file
case v of case v of
Just (currlink, sha, _type) Just (currlink, sha, _type)
| s2w8 link == L.unpack currlink -> | s2w8 link == L.unpack currlink ->

View file

@ -37,6 +37,7 @@ import Utility.Tmp
import Utility.Metered import Utility.Metered
import Utility.Matcher import Utility.Matcher
import qualified Data.ByteString.Char8 as S8
import qualified Data.ByteString.Lazy as L import qualified Data.ByteString.Lazy as L
import qualified Data.Map as M import qualified Data.Map as M
import Control.Concurrent import Control.Concurrent
@ -112,7 +113,7 @@ getExportCommit r treeish
return (fmap (tb, ) commitsha) return (fmap (tb, ) commitsha)
| otherwise = return Nothing | otherwise = return Nothing
where where
baseref = Ref $ takeWhile (/= ':') $ fromRef $ baseref = Ref $ S8.takeWhile (/= ':') $ fromRef' $
Git.Ref.removeBase refsheads treeish Git.Ref.removeBase refsheads treeish
refsheads = "refs/heads" refsheads = "refs/heads"

View file

@ -22,6 +22,6 @@ seek o = Find.seek o'
where where
o' = o o' = o
{ Find.keyOptions = Just $ WantBranchKeys $ { Find.keyOptions = Just $ WantBranchKeys $
map Git.Ref (Find.findThese o) map (Git.Ref . encodeBS') (Find.findThese o)
, Find.findThese = [] , Find.findThese = []
} }

View file

@ -66,7 +66,7 @@ optParser desc = do
[bs] -> [bs] ->
let (branch, subdir) = separate (== ':') bs let (branch, subdir) = separate (== ':') bs
in RemoteImportOptions r in RemoteImportOptions r
(Ref branch) (Ref (encodeBS' branch))
(if null subdir then Nothing else Just subdir) (if null subdir then Nothing else Just subdir)
_ -> giveup "expected BRANCH[:SUBDIR]" _ -> giveup "expected BRANCH[:SUBDIR]"

View file

@ -181,7 +181,7 @@ dirInfo o dir = showCustom (unwords ["info", dir]) $ do
treeishInfo :: InfoOptions -> String -> Annex () treeishInfo :: InfoOptions -> String -> Annex ()
treeishInfo o t = do treeishInfo o t = do
mi <- getTreeStatInfo o (Git.Ref t) mi <- getTreeStatInfo o (Git.Ref (encodeBS' t))
case mi of case mi of
Nothing -> noInfo t Nothing -> noInfo t
Just i -> showCustom (unwords ["info", t]) $ do Just i -> showCustom (unwords ["info", t]) $ do

View file

@ -264,7 +264,8 @@ parseGitRawLog config = parse epoch
parseRawChangeLine :: String -> Maybe (Git.Ref, Git.Ref) parseRawChangeLine :: String -> Maybe (Git.Ref, Git.Ref)
parseRawChangeLine = go . words parseRawChangeLine = go . words
where where
go (_:_:oldsha:newsha:_) = Just (Git.Ref oldsha, Git.Ref newsha) go (_:_:oldsha:newsha:_) =
Just (Git.Ref (encodeBS oldsha), Git.Ref (encodeBS newsha))
go _ = Nothing go _ = Nothing
parseTimeStamp :: String -> POSIXTime parseTimeStamp :: String -> POSIXTime

View file

@ -26,7 +26,7 @@ seek [] = do
commandAction mergeSyncedBranch commandAction mergeSyncedBranch
seek bs = do seek bs = do
prepMerge prepMerge
forM_ bs (commandAction . mergeBranch . Git.Ref) forM_ bs (commandAction . mergeBranch . Git.Ref . encodeBS')
mergeAnnexBranch :: CommandStart mergeAnnexBranch :: CommandStart
mergeAnnexBranch = starting "merge" (ActionItemOther (Just "git-annex")) $ do mergeAnnexBranch = starting "merge" (ActionItemOther (Just "git-annex")) $ do

View file

@ -13,6 +13,8 @@ import Git.Sha
import qualified Git.Branch import qualified Git.Branch
import Annex.AutoMerge import Annex.AutoMerge
import qualified Data.ByteString as S
cmd :: Command cmd :: Command
cmd = command "resolvemerge" SectionPlumbing cmd = command "resolvemerge" SectionPlumbing
"resolve merge conflicts" "resolve merge conflicts"
@ -27,7 +29,7 @@ start = starting "resolvemerge" (ActionItemOther Nothing) $ do
d <- fromRawFilePath <$> fromRepo Git.localGitDir d <- fromRawFilePath <$> fromRepo Git.localGitDir
let merge_head = d </> "MERGE_HEAD" let merge_head = d </> "MERGE_HEAD"
them <- fromMaybe (error nomergehead) . extractSha them <- fromMaybe (error nomergehead) . extractSha
<$> liftIO (readFile merge_head) <$> liftIO (S.readFile merge_head)
ifM (resolveMerge (Just us) them False) ifM (resolveMerge (Just us) them False)
( do ( do
void $ commitResolvedMerge Git.Branch.ManualCommit void $ commitResolvedMerge Git.Branch.ManualCommit

View file

@ -72,6 +72,8 @@ import Utility.Process.Transcript
import Control.Concurrent.MVar import Control.Concurrent.MVar
import qualified Data.Map as M import qualified Data.Map as M
import qualified Data.ByteString as S
import Data.Char
cmd :: Command cmd :: Command
cmd = withGlobalOptions [jobsOption] $ cmd = withGlobalOptions [jobsOption] $
@ -444,11 +446,11 @@ importRemote o mergeconfig remote currbranch
| otherwise = case remoteAnnexTrackingBranch (Remote.gitconfig remote) of | otherwise = case remoteAnnexTrackingBranch (Remote.gitconfig remote) of
Nothing -> noop Nothing -> noop
Just tb -> do Just tb -> do
let (b, s) = separate (== ':') (Git.fromRef tb) let (b, p) = separate' (== (fromIntegral (ord ':'))) (Git.fromRef' tb)
let branch = Git.Ref b let branch = Git.Ref b
let subdir = if null s let subdir = if S.null p
then Nothing then Nothing
else Just (asTopFilePath (toRawFilePath s)) else Just (asTopFilePath p)
Command.Import.seekRemote remote branch subdir Command.Import.seekRemote remote branch subdir
void $ mergeRemote remote currbranch mergeconfig o void $ mergeRemote remote currbranch mergeconfig o
where where

View file

@ -35,7 +35,7 @@ check = do
whenM ((/=) <$> liftIO (absPath top) <*> liftIO (absPath currdir)) $ whenM ((/=) <$> liftIO (absPath top) <*> liftIO (absPath currdir)) $
giveup "can only run uninit from the top of the git repository" giveup "can only run uninit from the top of the git repository"
where where
current_branch = Git.Ref . Prelude.head . lines . decodeBS' <$> revhead current_branch = Git.Ref . encodeBS' . Prelude.head . lines . decodeBS' <$> revhead
revhead = inRepo $ Git.Command.pipeReadStrict revhead = inRepo $ Git.Command.pipeReadStrict
[Param "rev-parse", Param "--abbrev-ref", Param "HEAD"] [Param "rev-parse", Param "--abbrev-ref", Param "HEAD"]

View file

@ -5,12 +5,10 @@
- Licensed under the GNU AGPL version 3 or higher. - Licensed under the GNU AGPL version 3 or higher.
-} -}
{-# LANGUAGE BangPatterns #-} {-# LANGUAGE BangPatterns, OverloadedStrings #-}
module Command.Unused where module Command.Unused where
import qualified Data.Map as M
import Command import Command
import Logs.Unused import Logs.Unused
import Annex.Content import Annex.Content
@ -37,6 +35,11 @@ import Annex.BloomFilter
import qualified Database.Keys import qualified Database.Keys
import Annex.InodeSentinal import Annex.InodeSentinal
import qualified Data.Map as M
import qualified Data.ByteString as S
import qualified Data.ByteString.Char8 as S8
import Data.Char
cmd :: Command cmd :: Command
cmd = command "unused" SectionMaintenance "look for unused file content" cmd = command "unused" SectionMaintenance "look for unused file content"
paramNothing (seek <$$> optParser) paramNothing (seek <$$> optParser)
@ -221,8 +224,7 @@ withKeysReferenced' mdir initial a = do
withKeysReferencedDiffGitRefs :: RefSpec -> (Key -> Annex ()) -> Annex () withKeysReferencedDiffGitRefs :: RefSpec -> (Key -> Annex ()) -> Annex ()
withKeysReferencedDiffGitRefs refspec a = do withKeysReferencedDiffGitRefs refspec a = do
rs <- relevantrefs . decodeBS' rs <- relevantrefs <$> inRepo (Git.Command.pipeReadStrict [Param "show-ref"])
<$> inRepo (Git.Command.pipeReadStrict [Param "show-ref"])
shaHead <- maybe (return Nothing) (inRepo . Git.Ref.sha) shaHead <- maybe (return Nothing) (inRepo . Git.Ref.sha)
=<< inRepo Git.Branch.currentUnsafe =<< inRepo Git.Branch.currentUnsafe
let haveHead = any (\(shaRef, _) -> Just shaRef == shaHead) rs let haveHead = any (\(shaRef, _) -> Just shaRef == shaHead) rs
@ -233,12 +235,12 @@ withKeysReferencedDiffGitRefs refspec a = do
where where
relevantrefs = map (\(r, h) -> (Git.Ref r, Git.Ref h)) . relevantrefs = map (\(r, h) -> (Git.Ref r, Git.Ref h)) .
filter ourbranches . filter ourbranches .
map (separate (== ' ')) . map (separate' (== (fromIntegral (ord ' ')))) .
lines S8.lines
nubRefs = nubBy (\(x, _) (y, _) -> x == y) nubRefs = nubBy (\(x, _) (y, _) -> x == y)
ourbranchend = '/' : Git.fromRef Annex.Branch.name ourbranchend = S.cons (fromIntegral (ord '/')) (Git.fromRef' Annex.Branch.name)
ourbranches (_, b) = not (ourbranchend `isSuffixOf` b) ourbranches (_, b) = not (ourbranchend `S.isSuffixOf` b)
&& not ("refs/synced/" `isPrefixOf` b) && not ("refs/synced/" `S.isPrefixOf` b)
&& not (is_branchView (Git.Ref b)) && not (is_branchView (Git.Ref b))
getreflog rs = inRepo $ Git.RefLog.getMulti rs getreflog rs = inRepo $ Git.RefLog.getMulti rs

View file

@ -6,6 +6,7 @@
-} -}
{-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE OverloadedStrings #-}
module Database.Keys ( module Database.Keys (
DbHandle, DbHandle,
@ -44,6 +45,7 @@ import Git.Types
import Git.Index import Git.Index
import qualified Data.ByteString as S import qualified Data.ByteString as S
import qualified Data.ByteString.Char8 as S8
import qualified System.FilePath.ByteString as P import qualified System.FilePath.ByteString as P
{- Runs an action that reads from the database. {- Runs an action that reads from the database.
@ -237,8 +239,8 @@ reconcileStaged qh = do
Nothing -> noop Nothing -> noop
where where
go cur indexcache = do go cur indexcache = do
(l, cleanup) <- inRepo $ pipeNullSplit diff (l, cleanup) <- inRepo $ pipeNullSplit' diff
changed <- procdiff (map decodeBL' l) False changed <- procdiff l False
void $ liftIO cleanup void $ liftIO cleanup
-- Flush database changes immediately -- Flush database changes immediately
-- so other processes can see them. -- so other processes can see them.
@ -278,15 +280,16 @@ reconcileStaged qh = do
, Param "--no-ext-diff" , Param "--no-ext-diff"
] ]
procdiff (info:file:rest) changed = case words info of procdiff (info:file:rest) changed
((':':_srcmode):dstmode:_srcsha:dstsha:_change:[]) | ":" `S.isPrefixOf` info = case S8.words info of
-- Only want files, not symlinks (_colonsrcmode:dstmode:_srcsha:dstsha:_change:[])
| dstmode /= decodeBS' (fmtTreeItemType TreeSymlink) -> do -- Only want files, not symlinks
maybe noop (reconcile (asTopFilePath (toRawFilePath file))) | dstmode /= fmtTreeItemType TreeSymlink -> do
=<< catKey (Ref dstsha) maybe noop (reconcile (asTopFilePath file))
procdiff rest True =<< catKey (Ref dstsha)
| otherwise -> procdiff rest changed procdiff rest True
_ -> return changed -- parse failed | otherwise -> procdiff rest changed
_ -> return changed -- parse failed
procdiff _ changed = return changed procdiff _ changed = return changed
-- Note that database writes done in here will not necessarily -- Note that database writes done in here will not necessarily

View file

@ -28,6 +28,7 @@ import Foreign.C.Types
import Key import Key
import Utility.InodeCache import Utility.InodeCache
import Utility.FileSize import Utility.FileSize
import Utility.FileSystemEncoding
import Git.Types import Git.Types
import Types.UUID import Types.UUID
import Types.Import import Types.Import
@ -94,10 +95,10 @@ newtype SSha = SSha String
deriving (Eq, Show) deriving (Eq, Show)
toSSha :: Sha -> SSha toSSha :: Sha -> SSha
toSSha (Ref s) = SSha s toSSha (Ref s) = SSha (decodeBS' s)
fromSSha :: SSha -> Ref fromSSha :: SSha -> Ref
fromSSha (SSha s) = Ref s fromSSha (SSha s) = Ref (encodeBS' s)
instance PersistField SSha where instance PersistField SSha where
toPersistValue (SSha b) = toPersistValue b toPersistValue (SSha b) = toPersistValue b

1
Git.hs
View file

@ -14,6 +14,7 @@ module Git (
Repo(..), Repo(..),
Ref(..), Ref(..),
fromRef, fromRef,
fromRef',
Branch, Branch,
Sha, Sha,
Tag, Tag,

View file

@ -18,6 +18,7 @@ import qualified Git.Config
import qualified Git.Ref import qualified Git.Ref
import qualified Data.ByteString as B import qualified Data.ByteString as B
import qualified Data.ByteString.Char8 as B8
{- The currently checked out branch. {- The currently checked out branch.
- -
@ -39,25 +40,27 @@ current r = do
{- The current branch, which may not really exist yet. -} {- The current branch, which may not really exist yet. -}
currentUnsafe :: Repo -> IO (Maybe Branch) currentUnsafe :: Repo -> IO (Maybe Branch)
currentUnsafe r = parse . firstLine' currentUnsafe r = parse . firstLine' <$> pipeReadStrict
<$> pipeReadStrict [Param "symbolic-ref", Param "-q", Param $ fromRef Git.Ref.headRef] r [ Param "symbolic-ref"
, Param "-q"
, Param $ fromRef Git.Ref.headRef
] r
where where
parse b parse b
| B.null b = Nothing | B.null b = Nothing
| otherwise = Just $ Git.Ref $ decodeBS b | otherwise = Just $ Git.Ref b
{- Checks if the second branch has any commits not present on the first {- Checks if the second branch has any commits not present on the first
- branch. -} - branch. -}
changed :: Branch -> Branch -> Repo -> IO Bool changed :: Branch -> Branch -> Repo -> IO Bool
changed origbranch newbranch repo changed origbranch newbranch repo
| origbranch == newbranch = return False | origbranch == newbranch = return False
| otherwise = not . null | otherwise = not . B.null
<$> changed' origbranch newbranch [Param "-n1"] repo <$> changed' origbranch newbranch [Param "-n1"] repo
where where
changed' :: Branch -> Branch -> [CommandParam] -> Repo -> IO String changed' :: Branch -> Branch -> [CommandParam] -> Repo -> IO B.ByteString
changed' origbranch newbranch extraps repo = changed' origbranch newbranch extraps repo = pipeReadStrict ps repo
decodeBS <$> pipeReadStrict ps repo
where where
ps = ps =
[ Param "log" [ Param "log"
@ -68,7 +71,7 @@ changed' origbranch newbranch extraps repo =
{- Lists commits that are in the second branch and not in the first branch. -} {- Lists commits that are in the second branch and not in the first branch. -}
changedCommits :: Branch -> Branch -> [CommandParam] -> Repo -> IO [Sha] changedCommits :: Branch -> Branch -> [CommandParam] -> Repo -> IO [Sha]
changedCommits origbranch newbranch extraps repo = changedCommits origbranch newbranch extraps repo =
catMaybes . map extractSha . lines catMaybes . map extractSha . B8.lines
<$> changed' origbranch newbranch extraps repo <$> changed' origbranch newbranch extraps repo
{- Check if it's possible to fast-forward from the old {- Check if it's possible to fast-forward from the old
@ -163,8 +166,7 @@ commitCommand' runner commitmode ps = runner $
-} -}
commit :: CommitMode -> Bool -> String -> Branch -> [Ref] -> Repo -> IO (Maybe Sha) commit :: CommitMode -> Bool -> String -> Branch -> [Ref] -> Repo -> IO (Maybe Sha)
commit commitmode allowempty message branch parentrefs repo = do commit commitmode allowempty message branch parentrefs repo = do
tree <- getSha "write-tree" $ tree <- getSha "write-tree" $ pipeReadStrict [Param "write-tree"] repo
decodeBS' <$> pipeReadStrict [Param "write-tree"] repo
ifM (cancommit tree) ifM (cancommit tree)
( do ( do
sha <- commitTree commitmode message parentrefs tree repo sha <- commitTree commitmode message parentrefs tree repo

View file

@ -5,6 +5,8 @@
- Licensed under the GNU AGPL version 3 or higher. - Licensed under the GNU AGPL version 3 or higher.
-} -}
{-# LANGUAGE OverloadedStrings #-}
module Git.CatFile ( module Git.CatFile (
CatFileHandle, CatFileHandle,
catFileStart, catFileStart,
@ -22,7 +24,6 @@ module Git.CatFile (
import System.IO import System.IO
import qualified Data.ByteString as S import qualified Data.ByteString as S
import qualified Data.ByteString.Lazy as L import qualified Data.ByteString.Lazy as L
import qualified Data.ByteString.Lazy.Char8 as L8
import qualified Data.Map as M import qualified Data.Map as M
import Data.String import Data.String
import Data.Char import Data.Char
@ -69,11 +70,11 @@ catFileStop h = do
{- Reads a file from a specified branch. -} {- Reads a file from a specified branch. -}
catFile :: CatFileHandle -> Branch -> RawFilePath -> IO L.ByteString catFile :: CatFileHandle -> Branch -> RawFilePath -> IO L.ByteString
catFile h branch file = catObject h $ Ref $ catFile h branch file = catObject h $ Ref $
fromRef branch ++ ":" ++ fromRawFilePath (toInternalGitPath file) fromRef' branch <> ":" <> toInternalGitPath file
catFileDetails :: CatFileHandle -> Branch -> RawFilePath -> IO (Maybe (L.ByteString, Sha, ObjectType)) catFileDetails :: CatFileHandle -> Branch -> RawFilePath -> IO (Maybe (L.ByteString, Sha, ObjectType))
catFileDetails h branch file = catObjectDetails h $ Ref $ catFileDetails h branch file = catObjectDetails h $ Ref $
fromRef branch ++ ":" ++ fromRawFilePath (toInternalGitPath file) fromRef' branch <> ":" <> toInternalGitPath file
{- Uses a running git cat-file read the content of an object. {- Uses a running git cat-file read the content of an object.
- Objects that do not exist will have "" returned. -} - Objects that do not exist will have "" returned. -}
@ -148,7 +149,7 @@ parseResp object l
| " missing" `isSuffixOf` l -- less expensive than full check | " missing" `isSuffixOf` l -- less expensive than full check
&& l == fromRef object ++ " missing" = Just DNE && l == fromRef object ++ " missing" = Just DNE
| otherwise = case words l of | otherwise = case words l of
[sha, objtype, size] -> case extractSha sha of [sha, objtype, size] -> case extractSha (encodeBS sha) of
Just sha' -> case (readObjectType (encodeBS objtype), reads size) of Just sha' -> case (readObjectType (encodeBS objtype), reads size) of
(Just t, [(bytes, "")]) -> (Just t, [(bytes, "")]) ->
Just $ ParsedResp sha' bytes t Just $ ParsedResp sha' bytes t
@ -218,39 +219,39 @@ catTree h treeref = go <$> catObjectDetails h treeref
catCommit :: CatFileHandle -> Ref -> IO (Maybe Commit) catCommit :: CatFileHandle -> Ref -> IO (Maybe Commit)
catCommit h commitref = go <$> catObjectDetails h commitref catCommit h commitref = go <$> catObjectDetails h commitref
where where
go (Just (b, _, CommitObject)) = parseCommit b go (Just (b, _, CommitObject)) = parseCommit (L.toStrict b)
go _ = Nothing go _ = Nothing
parseCommit :: L.ByteString -> Maybe Commit parseCommit :: S.ByteString -> Maybe Commit
parseCommit b = Commit parseCommit b = Commit
<$> (extractSha . L8.unpack =<< field "tree") <$> (extractSha =<< field "tree")
<*> Just (maybe [] (mapMaybe (extractSha . L8.unpack)) (fields "parent")) <*> Just (maybe [] (mapMaybe extractSha) (fields "parent"))
<*> (parsemetadata <$> field "author") <*> (parsemetadata <$> field "author")
<*> (parsemetadata <$> field "committer") <*> (parsemetadata <$> field "committer")
<*> Just (L8.unpack $ L.intercalate (L.singleton nl) message) <*> Just (decodeBS $ S.intercalate (S.singleton nl) message)
where where
field n = headMaybe =<< fields n field n = headMaybe =<< fields n
fields n = M.lookup (fromString n) fieldmap fields n = M.lookup (fromString n) fieldmap
fieldmap = M.fromListWith (++) ((map breakfield) header) fieldmap = M.fromListWith (++) ((map breakfield) header)
breakfield l = breakfield l =
let (k, sp_v) = L.break (== sp) l let (k, sp_v) = S.break (== sp) l
in (k, [L.drop 1 sp_v]) in (k, [S.drop 1 sp_v])
(header, message) = separate L.null ls (header, message) = separate S.null ls
ls = L.split nl b ls = S.split nl b
-- author and committer lines have the form: "name <email> date" -- author and committer lines have the form: "name <email> date"
-- The email is always present, even if empty "<>" -- The email is always present, even if empty "<>"
parsemetadata l = CommitMetaData parsemetadata l = CommitMetaData
{ commitName = whenset $ L.init name_sp { commitName = whenset $ S.init name_sp
, commitEmail = whenset email , commitEmail = whenset email
, commitDate = whenset $ L.drop 2 gt_sp_date , commitDate = whenset $ S.drop 2 gt_sp_date
} }
where where
(name_sp, rest) = L.break (== lt) l (name_sp, rest) = S.break (== lt) l
(email, gt_sp_date) = L.break (== gt) (L.drop 1 rest) (email, gt_sp_date) = S.break (== gt) (S.drop 1 rest)
whenset v whenset v
| L.null v = Nothing | S.null v = Nothing
| otherwise = Just (L8.unpack v) | otherwise = Just (decodeBS v)
nl = fromIntegral (ord '\n') nl = fromIntegral (ord '\n')
sp = fromIntegral (ord ' ') sp = fromIntegral (ord ' ')

View file

@ -81,11 +81,16 @@ pipeReadStrict' reader params repo = assertLocal repo $
{- Runs a git command, feeding it an input, and returning its output, {- Runs a git command, feeding it an input, and returning its output,
- which is expected to be fairly small, since it's all read into memory - which is expected to be fairly small, since it's all read into memory
- strictly. -} - strictly. -}
pipeWriteRead :: [CommandParam] -> Maybe (Handle -> IO ()) -> Repo -> IO String pipeWriteRead :: [CommandParam] -> Maybe (Handle -> IO ()) -> Repo -> IO S.ByteString
pipeWriteRead params writer repo = assertLocal repo $ pipeWriteRead params writer repo = assertLocal repo $
writeReadProcessEnv "git" (toCommand $ gitCommandLine params repo) writeReadProcessEnv "git" (toCommand $ gitCommandLine params repo)
(gitEnv repo) writer (Just adjusthandle) (gitEnv repo) writer'
where where
writer' = case writer of
Nothing -> Nothing
Just a -> Just $ \h -> do
adjusthandle h
a h
adjusthandle h = hSetNewlineMode h noNewlineTranslation adjusthandle h = hSetNewlineMode h noNewlineTranslation
{- Runs a git command, feeding it input on a handle with an action. -} {- Runs a git command, feeding it input on a handle with an action. -}

View file

@ -58,7 +58,7 @@ urlCredential = Credential . M.singleton "url"
runCredential :: String -> Credential -> Repo -> IO Credential runCredential :: String -> Credential -> Repo -> IO Credential
runCredential action input r = runCredential action input r =
parseCredential <$> pipeWriteRead parseCredential . decodeBS <$> pipeWriteRead
[ Param "credential" [ Param "credential"
, Param action , Param action
] ]

View file

@ -1,6 +1,6 @@
{- git diff-tree interface {- git diff-tree interface
- -
- Copyright 2012 Joey Hess <id@joeyh.name> - Copyright 2012-2020 Joey Hess <id@joeyh.name>
- -
- Licensed under the GNU AGPL version 3 or higher. - Licensed under the GNU AGPL version 3 or higher.
-} -}
@ -17,7 +17,9 @@ module Git.DiffTree (
commitDiff, commitDiff,
) where ) where
import Numeric import qualified Data.ByteString.Lazy as L
import qualified Data.Attoparsec.ByteString.Lazy as A
import qualified Data.Attoparsec.ByteString.Char8 as A8
import Common import Common
import Git import Git
@ -27,6 +29,7 @@ import Git.FilePath
import Git.DiffTreeItem import Git.DiffTreeItem
import qualified Git.Filename import qualified Git.Filename
import qualified Git.Ref import qualified Git.Ref
import Utility.Attoparsec
{- Checks if the DiffTreeItem modifies a file with a given name {- Checks if the DiffTreeItem modifies a file with a given name
- or under a directory by that name. -} - or under a directory by that name. -}
@ -89,7 +92,7 @@ commitDiff ref = getdiff (Param "show")
getdiff :: CommandParam -> [CommandParam] -> Repo -> IO ([DiffTreeItem], IO Bool) getdiff :: CommandParam -> [CommandParam] -> Repo -> IO ([DiffTreeItem], IO Bool)
getdiff command params repo = do getdiff command params repo = do
(diff, cleanup) <- pipeNullSplit ps repo (diff, cleanup) <- pipeNullSplit ps repo
return (parseDiffRaw (map decodeBL diff), cleanup) return (parseDiffRaw diff, cleanup)
where where
ps = ps =
command : command :
@ -100,26 +103,28 @@ getdiff command params repo = do
params params
{- Parses --raw output used by diff-tree and git-log. -} {- Parses --raw output used by diff-tree and git-log. -}
parseDiffRaw :: [String] -> [DiffTreeItem] parseDiffRaw :: [L.ByteString] -> [DiffTreeItem]
parseDiffRaw l = go l parseDiffRaw l = go l
where where
go [] = [] go [] = []
go (info:f:rest) = mk info f : go rest go (info:f:rest) = case A.parse (parserDiffRaw (L.toStrict f)) info of
go (s:[]) = error $ "diff-tree parse error near \"" ++ s ++ "\"" A.Done _ r -> r : go rest
A.Fail _ _ err -> error $ "diff-tree parse error: " ++ err
go (s:[]) = error $ "diff-tree parse error near \"" ++ decodeBL' s ++ "\""
mk info f = DiffTreeItem -- :<srcmode> SP <dstmode> SP <srcsha> SP <dstsha> SP <status>
{ srcmode = readmode srcm parserDiffRaw :: RawFilePath -> A.Parser DiffTreeItem
, dstmode = readmode dstm parserDiffRaw f = DiffTreeItem
, srcsha = fromMaybe (error "bad srcsha") $ extractSha ssha <$ A8.char ':'
, dstsha = fromMaybe (error "bad dstsha") $ extractSha dsha <*> octal
, status = s <* A8.char ' '
, file = asTopFilePath $ fromInternalGitPath $ Git.Filename.decode $ toRawFilePath f <*> octal
} <* A8.char ' '
where <*> (maybe (fail "bad srcsha") return . extractSha =<< nextword)
readmode = fst . Prelude.head . readOct <* A8.char ' '
<*> (maybe (fail "bad dstsha") return . extractSha =<< nextword)
-- info = :<srcmode> SP <dstmode> SP <srcsha> SP <dstsha> SP <status> <* A8.char ' '
(srcm, past_srcm) = splitAt 7 $ drop 1 info <*> A.takeByteString
(dstm, past_dstm) = splitAt 7 past_srcm <*> pure (asTopFilePath $ fromInternalGitPath $ Git.Filename.decode f)
(ssha, past_ssha) = separate (== ' ') past_dstm where
(dsha, s) = separate (== ' ') past_ssha nextword = A8.takeTill (== ' ')

View file

@ -10,6 +10,7 @@ module Git.DiffTreeItem (
) where ) where
import System.Posix.Types import System.Posix.Types
import qualified Data.ByteString as S
import Git.FilePath import Git.FilePath
import Git.Types import Git.Types
@ -19,6 +20,6 @@ data DiffTreeItem = DiffTreeItem
, dstmode :: FileMode , dstmode :: FileMode
, srcsha :: Sha -- null sha if file was added , srcsha :: Sha -- null sha if file was added
, dstsha :: Sha -- null sha if file was deleted , dstsha :: Sha -- null sha if file was deleted
, status :: String , status :: S.ByteString
, file :: TopFilePath , file :: TopFilePath
} deriving Show } deriving Show

View file

@ -50,7 +50,7 @@ data BranchFilePath = BranchFilePath Ref TopFilePath
{- Git uses the branch:file form to refer to a BranchFilePath -} {- Git uses the branch:file form to refer to a BranchFilePath -}
descBranchFilePath :: BranchFilePath -> S.ByteString descBranchFilePath :: BranchFilePath -> S.ByteString
descBranchFilePath (BranchFilePath b f) = descBranchFilePath (BranchFilePath b f) =
encodeBS' (fromRef b) <> ":" <> getTopFilePath f fromRef' b <> ":" <> getTopFilePath f
{- Path to a TopFilePath, within the provided git repo. -} {- Path to a TopFilePath, within the provided git repo. -}
fromTopFilePath :: TopFilePath -> Git.Repo -> RawFilePath fromTopFilePath :: TopFilePath -> Git.Repo -> RawFilePath

View file

@ -139,7 +139,8 @@ isMissing s r = either (const True) (const False) <$> tryIO dump
] r ] r
findShas :: [String] -> [Sha] findShas :: [String] -> [Sha]
findShas = catMaybes . map extractSha . concat . map words . filter wanted findShas = catMaybes . map (extractSha . encodeBS')
. concat . map words . filter wanted
where where
wanted l = not ("dangling " `isPrefixOf` l) wanted l = not ("dangling " `isPrefixOf` l)

View file

@ -18,6 +18,7 @@ import qualified Utility.CoProcess as CoProcess
import Utility.Tmp import Utility.Tmp
import qualified Data.ByteString as S import qualified Data.ByteString as S
import qualified Data.ByteString.Char8 as S8
import qualified Data.ByteString.Lazy as L import qualified Data.ByteString.Lazy as L
import Data.ByteString.Builder import Data.ByteString.Builder
@ -39,7 +40,7 @@ hashFile :: HashObjectHandle -> FilePath -> IO Sha
hashFile h file = CoProcess.query h send receive hashFile h file = CoProcess.query h send receive
where where
send to = hPutStrLn to =<< absPath file send to = hPutStrLn to =<< absPath file
receive from = getSha "hash-object" $ hGetLine from receive from = getSha "hash-object" $ S8.hGetLine from
class HashableBlob t where class HashableBlob t where
hashableBlobToHandle :: Handle -> t -> IO () hashableBlobToHandle :: Handle -> t -> IO ()

View file

@ -15,6 +15,9 @@ import Git.Command
import Git.Sha import Git.Sha
import qualified Data.Set as S import qualified Data.Set as S
import qualified Data.ByteString.Lazy as L
import qualified Data.ByteString.Char8 as B8
import qualified Data.ByteString.Lazy.Char8 as L8
data History t = History t (S.Set (History t)) data History t = History t (S.Set (History t))
deriving (Show, Eq, Ord) deriving (Show, Eq, Ord)
@ -53,8 +56,9 @@ getHistoryToDepth n commit r = do
!h <- fmap (truncateHistoryToDepth n) !h <- fmap (truncateHistoryToDepth n)
. build Nothing . build Nothing
. map parsehistorycommit . map parsehistorycommit
. lines . map L.toStrict
<$> hGetContents inh . L8.lines
<$> L.hGetContents inh
hClose inh hClose inh
void $ waitForProcess pid void $ waitForProcess pid
return h return h
@ -93,7 +97,7 @@ getHistoryToDepth n commit r = do
, Param "--format=%T %H %P" , Param "--format=%T %H %P"
] ]
parsehistorycommit l = case map extractSha (splitc ' ' l) of parsehistorycommit l = case map extractSha (B8.split ' ' l) of
(Just t:Just c:ps) -> Just $ (Just t:Just c:ps) -> Just $
( HistoryCommit ( HistoryCommit
{ historyCommit = c { historyCommit = c

View file

@ -36,9 +36,10 @@ import Utility.InodeCache
import Utility.TimeStamp import Utility.TimeStamp
import Numeric import Numeric
import Data.Char
import System.Posix.Types import System.Posix.Types
import qualified Data.Map as M import qualified Data.Map as M
import qualified Data.ByteString.Lazy as L import qualified Data.ByteString as S
{- It's only safe to use git ls-files on the current repo, not on a remote. {- It's only safe to use git ls-files on the current repo, not on a remote.
- -
@ -81,7 +82,7 @@ inRepo' ps l repo = guardSafeForLsFiles repo $ pipeNullSplit' params repo
{- Files that are checked into the index or have been committed to a {- Files that are checked into the index or have been committed to a
- branch. -} - branch. -}
inRepoOrBranch :: Branch -> [RawFilePath] -> Repo -> IO ([RawFilePath], IO Bool) inRepoOrBranch :: Branch -> [RawFilePath] -> Repo -> IO ([RawFilePath], IO Bool)
inRepoOrBranch (Ref b) = inRepo' [Param $ "--with-tree=" ++ b] inRepoOrBranch b = inRepo' [Param $ "--with-tree=" ++ fromRef b]
{- Scans for files at the specified locations that are not checked into git. -} {- Scans for files at the specified locations that are not checked into git. -}
notInRepo :: Bool -> [RawFilePath] -> Repo -> IO ([RawFilePath], IO Bool) notInRepo :: Bool -> [RawFilePath] -> Repo -> IO ([RawFilePath], IO Bool)
@ -189,21 +190,21 @@ stagedDetails = stagedDetails' []
- contents. -} - contents. -}
stagedDetails' :: [CommandParam] -> [RawFilePath] -> Repo -> IO ([StagedDetails], IO Bool) stagedDetails' :: [CommandParam] -> [RawFilePath] -> Repo -> IO ([StagedDetails], IO Bool)
stagedDetails' ps l repo = guardSafeForLsFiles repo $ do stagedDetails' ps l repo = guardSafeForLsFiles repo $ do
(ls, cleanup) <- pipeNullSplit params repo (ls, cleanup) <- pipeNullSplit' params repo
return (map parseStagedDetails ls, cleanup) return (map parseStagedDetails ls, cleanup)
where where
params = Param "ls-files" : Param "--stage" : Param "-z" : ps ++ params = Param "ls-files" : Param "--stage" : Param "-z" : ps ++
Param "--" : map (File . fromRawFilePath) l Param "--" : map (File . fromRawFilePath) l
parseStagedDetails :: L.ByteString -> StagedDetails parseStagedDetails :: S.ByteString -> StagedDetails
parseStagedDetails s parseStagedDetails s
| null file = (L.toStrict s, Nothing, Nothing) | S.null file = (s, Nothing, Nothing)
| otherwise = (toRawFilePath file, extractSha sha, readmode mode) | otherwise = (file, extractSha sha, readmode mode)
where where
(metadata, file) = separate (== '\t') (decodeBL' s) (metadata, file) = separate' (== fromIntegral (ord '\t')) s
(mode, metadata') = separate (== ' ') metadata (mode, metadata') = separate' (== fromIntegral (ord ' ')) metadata
(sha, _) = separate (== ' ') metadata' (sha, _) = separate' (== fromIntegral (ord ' ')) metadata'
readmode = fst <$$> headMaybe . readOct readmode = fst <$$> headMaybe . readOct . decodeBS'
{- Returns a list of the files in the specified locations that are staged {- Returns a list of the files in the specified locations that are staged
- for commit, and whose type has changed. -} - for commit, and whose type has changed. -}
@ -284,7 +285,7 @@ parseUnmerged s
then Nothing then Nothing
else do else do
treeitemtype <- readTreeItemType (encodeBS rawtreeitemtype) treeitemtype <- readTreeItemType (encodeBS rawtreeitemtype)
sha <- extractSha rawsha sha <- extractSha (encodeBS' rawsha)
return $ InternalUnmerged (stage == 2) (toRawFilePath file) return $ InternalUnmerged (stage == 2) (toRawFilePath file)
(Just treeitemtype) (Just sha) (Just treeitemtype) (Just sha)
_ -> Nothing _ -> Nothing

View file

@ -96,7 +96,7 @@ parserLsTree = TreeItem
<*> A8.takeTill (== ' ') <*> A8.takeTill (== ' ')
<* A8.char ' ' <* A8.char ' '
-- sha -- sha
<*> (Ref . decodeBS' <$> A8.takeTill (== '\t')) <*> (Ref <$> A8.takeTill (== '\t'))
<* A8.char '\t' <* A8.char '\t'
-- file -- file
<*> (asTopFilePath . Git.Filename.decode <$> A.takeByteString) <*> (asTopFilePath . Git.Filename.decode <$> A.takeByteString)

View file

@ -26,7 +26,7 @@ listPackFiles r = filter (".pack" `isSuffixOf`)
listLooseObjectShas :: Repo -> IO [Sha] listLooseObjectShas :: Repo -> IO [Sha]
listLooseObjectShas r = catchDefaultIO [] $ listLooseObjectShas r = catchDefaultIO [] $
mapMaybe (extractSha . concat . reverse . take 2 . reverse . splitDirectories) mapMaybe (extractSha . encodeBS . concat . reverse . take 2 . reverse . splitDirectories)
<$> dirContentsRecursiveSkipping (== "pack") True (objectsDir r) <$> dirContentsRecursiveSkipping (== "pack") True (objectsDir r)
looseObjectFile :: Repo -> Sha -> FilePath looseObjectFile :: Repo -> Sha -> FilePath

View file

@ -17,6 +17,7 @@ import Git.Types
import Data.Char (chr, ord) import Data.Char (chr, ord)
import qualified Data.ByteString as S import qualified Data.ByteString as S
import qualified Data.ByteString.Char8 as S8
headRef :: Ref headRef :: Ref
headRef = Ref "HEAD" headRef = Ref "HEAD"
@ -25,7 +26,7 @@ headFile :: Repo -> FilePath
headFile r = fromRawFilePath (localGitDir r) </> "HEAD" headFile r = fromRawFilePath (localGitDir r) </> "HEAD"
setHeadRef :: Ref -> Repo -> IO () setHeadRef :: Ref -> Repo -> IO ()
setHeadRef ref r = writeFile (headFile r) ("ref: " ++ fromRef ref) setHeadRef ref r = S.writeFile (headFile r) ("ref: " <> fromRef' ref)
{- Converts a fully qualified git ref into a user-visible string. -} {- Converts a fully qualified git ref into a user-visible string. -}
describe :: Ref -> String describe :: Ref -> String
@ -41,10 +42,11 @@ base = removeBase "refs/heads/" . removeBase "refs/remotes/"
{- Removes a directory such as "refs/heads/master" from a {- Removes a directory such as "refs/heads/master" from a
- fully qualified ref. Any ref not starting with it is left as-is. -} - fully qualified ref. Any ref not starting with it is left as-is. -}
removeBase :: String -> Ref -> Ref removeBase :: String -> Ref -> Ref
removeBase dir (Ref r) removeBase dir r
| prefix `isPrefixOf` r = Ref (drop (length prefix) r) | prefix `isPrefixOf` rs = Ref $ encodeBS $ drop (length prefix) rs
| otherwise = Ref r | otherwise = r
where where
rs = fromRef r
prefix = case end dir of prefix = case end dir of
['/'] -> dir ['/'] -> dir
_ -> dir ++ "/" _ -> dir ++ "/"
@ -53,7 +55,7 @@ removeBase dir (Ref r)
- refs/heads/master, yields a version of that ref under the directory, - refs/heads/master, yields a version of that ref under the directory,
- such as refs/remotes/origin/master. -} - such as refs/remotes/origin/master. -}
underBase :: String -> Ref -> Ref underBase :: String -> Ref -> Ref
underBase dir r = Ref $ dir ++ "/" ++ fromRef (base r) underBase dir r = Ref $ encodeBS dir <> "/" <> fromRef' (base r)
{- Convert a branch such as "master" into a fully qualified ref. -} {- Convert a branch such as "master" into a fully qualified ref. -}
branchRef :: Branch -> Ref branchRef :: Branch -> Ref
@ -66,21 +68,25 @@ branchRef = underBase "refs/heads"
- of a repo. - of a repo.
-} -}
fileRef :: RawFilePath -> Ref fileRef :: RawFilePath -> Ref
fileRef f = Ref $ ":./" ++ fromRawFilePath f fileRef f = Ref $ ":./" <> f
{- Converts a Ref to refer to the content of the Ref on a given date. -} {- Converts a Ref to refer to the content of the Ref on a given date. -}
dateRef :: Ref -> RefDate -> Ref dateRef :: Ref -> RefDate -> Ref
dateRef (Ref r) (RefDate d) = Ref $ r ++ "@" ++ d dateRef r (RefDate d) = Ref $ fromRef' r <> "@" <> encodeBS' d
{- A Ref that can be used to refer to a file in the repository as it {- A Ref that can be used to refer to a file in the repository as it
- appears in a given Ref. -} - appears in a given Ref. -}
fileFromRef :: Ref -> RawFilePath -> Ref fileFromRef :: Ref -> RawFilePath -> Ref
fileFromRef (Ref r) f = let (Ref fr) = fileRef f in Ref (r ++ fr) fileFromRef r f = let (Ref fr) = fileRef f in Ref (fromRef' r <> fr)
{- Checks if a ref exists. -} {- Checks if a ref exists. -}
exists :: Ref -> Repo -> IO Bool exists :: Ref -> Repo -> IO Bool
exists ref = runBool exists ref = runBool
[Param "show-ref", Param "--verify", Param "-q", Param $ fromRef ref] [ Param "show-ref"
, Param "--verify"
, Param "-q"
, Param $ fromRef ref
]
{- The file used to record a ref. (Git also stores some refs in a {- The file used to record a ref. (Git also stores some refs in a
- packed-refs file.) -} - packed-refs file.) -}
@ -107,26 +113,26 @@ sha branch repo = process <$> showref repo
] ]
process s process s
| S.null s = Nothing | S.null s = Nothing
| otherwise = Just $ Ref $ decodeBS' $ firstLine' s | otherwise = Just $ Ref $ firstLine' s
headSha :: Repo -> IO (Maybe Sha) headSha :: Repo -> IO (Maybe Sha)
headSha = sha headRef headSha = sha headRef
{- List of (shas, branches) matching a given ref or refs. -} {- List of (shas, branches) matching a given ref or refs. -}
matching :: [Ref] -> Repo -> IO [(Sha, Branch)] matching :: [Ref] -> Repo -> IO [(Sha, Branch)]
matching refs repo = matching' (map fromRef refs) repo matching = matching' []
{- Includes HEAD in the output, if asked for it. -} {- Includes HEAD in the output, if asked for it. -}
matchingWithHEAD :: [Ref] -> Repo -> IO [(Sha, Branch)] matchingWithHEAD :: [Ref] -> Repo -> IO [(Sha, Branch)]
matchingWithHEAD refs repo = matching' ("--head" : map fromRef refs) repo matchingWithHEAD = matching' [Param "--head"]
{- List of (shas, branches) matching a given ref spec. -} matching' :: [CommandParam] -> [Ref] -> Repo -> IO [(Sha, Branch)]
matching' :: [String] -> Repo -> IO [(Sha, Branch)] matching' ps rs repo = map gen . S8.lines <$>
matching' ps repo = map gen . lines . decodeBS' <$> pipeReadStrict (Param "show-ref" : ps ++ rps) repo
pipeReadStrict (Param "show-ref" : map Param ps) repo
where where
gen l = let (r, b) = separate (== ' ') l gen l = let (r, b) = separate' (== fromIntegral (ord ' ')) l
in (Ref r, Ref b) in (Ref r, Ref b)
rps = map (Param . fromRef) rs
{- List of (shas, branches) matching a given ref. {- List of (shas, branches) matching a given ref.
- Duplicate shas are filtered out. -} - Duplicate shas are filtered out. -}
@ -137,7 +143,7 @@ matchingUniq refs repo = nubBy uniqref <$> matching refs repo
{- List of all refs. -} {- List of all refs. -}
list :: Repo -> IO [(Sha, Ref)] list :: Repo -> IO [(Sha, Ref)]
list = matching' [] list = matching' [] []
{- Deletes a ref. This can delete refs that are not branches, {- Deletes a ref. This can delete refs that are not branches,
- which git branch --delete refuses to delete. -} - which git branch --delete refuses to delete. -}
@ -154,13 +160,17 @@ delete oldvalue ref = run
- The ref may be something like a branch name, and it could contain - The ref may be something like a branch name, and it could contain
- ":subdir" if a subtree is wanted. -} - ":subdir" if a subtree is wanted. -}
tree :: Ref -> Repo -> IO (Maybe Sha) tree :: Ref -> Repo -> IO (Maybe Sha)
tree (Ref ref) = extractSha . decodeBS <$$> pipeReadStrict tree (Ref ref) = extractSha <$$> pipeReadStrict
[ Param "rev-parse", Param "--verify", Param "--quiet", Param ref' ] [ Param "rev-parse"
, Param "--verify"
, Param "--quiet"
, Param (decodeBS' ref')
]
where where
ref' = if ":" `isInfixOf` ref ref' = if ":" `S.isInfixOf` ref
then ref then ref
-- de-reference commit objects to the tree -- de-reference commit objects to the tree
else ref ++ ":" else ref <> ":"
{- Checks if a String is a legal git ref name. {- Checks if a String is a legal git ref name.
- -

View file

@ -12,6 +12,9 @@ import Git
import Git.Command import Git.Command
import Git.Sha import Git.Sha
import qualified Data.ByteString as S
import qualified Data.ByteString.Char8 as S8
{- Gets the reflog for a given branch. -} {- Gets the reflog for a given branch. -}
get :: Branch -> Repo -> IO [Sha] get :: Branch -> Repo -> IO [Sha]
get b = getMulti [b] get b = getMulti [b]
@ -21,7 +24,7 @@ getMulti :: [Branch] -> Repo -> IO [Sha]
getMulti bs = get' (map (Param . fromRef) bs) getMulti bs = get' (map (Param . fromRef) bs)
get' :: [CommandParam] -> Repo -> IO [Sha] get' :: [CommandParam] -> Repo -> IO [Sha]
get' ps = mapMaybe extractSha . lines . decodeBS <$$> pipeReadStrict ps' get' ps = mapMaybe (extractSha . S.copy) . S8.lines <$$> pipeReadStrict ps'
where where
ps' = catMaybes ps' = catMaybes
[ Just $ Param "log" [ Just $ Param "log"

View file

@ -232,7 +232,7 @@ getAllRefs r = getAllRefs' (fromRawFilePath (localGitDir r) </> "refs")
getAllRefs' :: FilePath -> IO [Ref] getAllRefs' :: FilePath -> IO [Ref]
getAllRefs' refdir = do getAllRefs' refdir = do
let topsegs = length (splitPath refdir) - 1 let topsegs = length (splitPath refdir) - 1
let toref = Ref . joinPath . drop topsegs . splitPath let toref = Ref . encodeBS' . joinPath . drop topsegs . splitPath
map toref <$> dirContentsRecursive refdir map toref <$> dirContentsRecursive refdir
explodePackedRefsFile :: Repo -> IO () explodePackedRefsFile :: Repo -> IO ()
@ -257,8 +257,8 @@ packedRefsFile r = fromRawFilePath (localGitDir r) </> "packed-refs"
parsePacked :: String -> Maybe (Sha, Ref) parsePacked :: String -> Maybe (Sha, Ref)
parsePacked l = case words l of parsePacked l = case words l of
(sha:ref:[]) (sha:ref:[])
| isJust (extractSha sha) && Ref.legal True ref -> | isJust (extractSha (encodeBS' sha)) && Ref.legal True ref ->
Just (Ref sha, Ref ref) Just (Ref (encodeBS' sha), Ref (encodeBS' ref))
_ -> Nothing _ -> Nothing
{- git-branch -d cannot be used to remove a branch that is directly {- git-branch -d cannot be used to remove a branch that is directly
@ -279,13 +279,13 @@ findUncorruptedCommit missing goodcommits branch r = do
if ok if ok
then return (Just branch, goodcommits') then return (Just branch, goodcommits')
else do else do
(ls, cleanup) <- pipeNullSplit (ls, cleanup) <- pipeNullSplit'
[ Param "log" [ Param "log"
, Param "-z" , Param "-z"
, Param "--format=%H" , Param "--format=%H"
, Param (fromRef branch) , Param (fromRef branch)
] r ] r
let branchshas = catMaybes $ map (extractSha . decodeBL) ls let branchshas = catMaybes $ map extractSha ls
reflogshas <- RefLog.get branch r reflogshas <- RefLog.get branch r
-- XXX Could try a bit harder here, and look -- XXX Could try a bit harder here, and look
-- for uncorrupted old commits in branches in the -- for uncorrupted old commits in branches in the
@ -328,8 +328,8 @@ verifyCommit missing goodcommits commit r
where where
parse l = case words l of parse l = case words l of
(commitsha:treesha:[]) -> (,) (commitsha:treesha:[]) -> (,)
<$> extractSha commitsha <$> extractSha (encodeBS' commitsha)
<*> extractSha treesha <*> extractSha (encodeBS' treesha)
_ -> Nothing _ -> Nothing
check [] = return True check [] = return True
check ((c, t):rest) check ((c, t):rest)
@ -448,7 +448,8 @@ preRepair g = do
void $ tryIO $ allowWrite f void $ tryIO $ allowWrite f
where where
headfile = fromRawFilePath (localGitDir g) </> "HEAD" headfile = fromRawFilePath (localGitDir g) </> "HEAD"
validhead s = "ref: refs/" `isPrefixOf` s || isJust (extractSha s) validhead s = "ref: refs/" `isPrefixOf` s
|| isJust (extractSha (encodeBS' s))
{- Put it all together. -} {- Put it all together. -}
runRepair :: (Ref -> Bool) -> Bool -> Repo -> IO (Bool, [Branch]) runRepair :: (Ref -> Bool) -> Bool -> Repo -> IO (Bool, [Branch])

View file

@ -5,31 +5,43 @@
- Licensed under the GNU AGPL version 3 or higher. - Licensed under the GNU AGPL version 3 or higher.
-} -}
{-# LANGUAGE OverloadedStrings #-}
module Git.Sha where module Git.Sha where
import Common import Common
import Git.Types import Git.Types
import qualified Data.ByteString as S
import Data.Char
{- Runs an action that causes a git subcommand to emit a Sha, and strips {- Runs an action that causes a git subcommand to emit a Sha, and strips
- any trailing newline, returning the sha. -} - any trailing newline, returning the sha. -}
getSha :: String -> IO String -> IO Sha getSha :: String -> IO S.ByteString -> IO Sha
getSha subcommand a = maybe bad return =<< extractSha <$> a getSha subcommand a = maybe bad return =<< extractSha <$> a
where where
bad = error $ "failed to read sha from git " ++ subcommand bad = error $ "failed to read sha from git " ++ subcommand
{- Extracts the Sha from a string. There can be a trailing newline after {- Extracts the Sha from a ByteString.
- it, but nothing else. -} -
extractSha :: String -> Maybe Sha - There can be a trailing newline after it, but nothing else.
-}
extractSha :: S.ByteString -> Maybe Sha
extractSha s extractSha s
| len `elem` shaSizes = val s | len `elem` shaSizes = val s
| len - 1 `elem` shaSizes && length s' == len - 1 = val s' | len - 1 `elem` shaSizes && S.length s' == len - 1 = val s'
| otherwise = Nothing | otherwise = Nothing
where where
len = length s len = S.length s
s' = firstLine s s' = firstLine' s
val v val v
| all (`elem` "1234567890ABCDEFabcdef") v = Just $ Ref v | S.all validinsha v = Just $ Ref v
| otherwise = Nothing | otherwise = Nothing
validinsha w = or
[ w >= 48 && w <= 57 -- 0-9
, w >= 97 && w <= 102 -- a-f
, w >= 65 && w <= 70 -- A-F
]
{- Sizes of git shas. -} {- Sizes of git shas. -}
shaSizes :: [Int] shaSizes :: [Int]
@ -41,7 +53,9 @@ shaSizes =
{- Git plumbing often uses a all 0 sha to represent things like a {- Git plumbing often uses a all 0 sha to represent things like a
- deleted file. -} - deleted file. -}
nullShas :: [Sha] nullShas :: [Sha]
nullShas = map (\n -> Ref (replicate n '0')) shaSizes nullShas = map (\n -> Ref (S.replicate n zero)) shaSizes
where
zero = fromIntegral (ord '0')
{- Sha to provide to git plumbing when deleting a file. {- Sha to provide to git plumbing when deleting a file.
- -

View file

@ -38,6 +38,7 @@ import System.Posix.Types
import Control.Monad.IO.Class import Control.Monad.IO.Class
import qualified Data.Set as S import qualified Data.Set as S
import qualified Data.Map as M import qualified Data.Map as M
import qualified Data.ByteString.Char8 as S8
newtype Tree = Tree [TreeContent] newtype Tree = Tree [TreeContent]
deriving (Show) deriving (Show)
@ -106,7 +107,7 @@ mkTree (MkTreeHandle cp) l = CoProcess.query cp send receive
NewSubTree _ _ -> error "recordSubTree internal error; unexpected NewSubTree" NewSubTree _ _ -> error "recordSubTree internal error; unexpected NewSubTree"
TreeCommit f fm s -> mkTreeOutput fm CommitObject s f TreeCommit f fm s -> mkTreeOutput fm CommitObject s f
hPutStr h "\NUL" -- signal end of tree to --batch hPutStr h "\NUL" -- signal end of tree to --batch
receive h = getSha "mktree" (hGetLine h) receive h = getSha "mktree" (S8.hGetLine h)
treeMode :: FileMode treeMode :: FileMode
treeMode = 0o040000 treeMode = 0o040000

View file

@ -81,11 +81,14 @@ instance IsString ConfigValue where
type RemoteName = String type RemoteName = String
{- A git ref. Can be a sha1, or a branch or tag name. -} {- A git ref. Can be a sha1, or a branch or tag name. -}
newtype Ref = Ref String newtype Ref = Ref S.ByteString
deriving (Eq, Ord, Read, Show) deriving (Eq, Ord, Read, Show)
fromRef :: Ref -> String fromRef :: Ref -> String
fromRef (Ref s) = s fromRef = decodeBS' . fromRef'
fromRef' :: Ref -> S.ByteString
fromRef' (Ref s) = s
{- Aliases for Ref. -} {- Aliases for Ref. -}
type Branch = Ref type Branch = Ref

View file

@ -10,8 +10,10 @@ module Git.UnionMerge (
mergeIndex mergeIndex
) where ) where
import qualified Data.ByteString as S
import qualified Data.ByteString.Lazy as L import qualified Data.ByteString.Lazy as L
import qualified Data.ByteString.Lazy.Char8 as L8 import qualified Data.ByteString.Lazy.Char8 as L8
import qualified Data.ByteString.Char8 as S8
import qualified Data.Set as S import qualified Data.Set as S
import Common import Common
@ -54,13 +56,13 @@ mergeIndex hashhandle ch repo bs = forM_ bs $ \b ->
{- For merging two trees. -} {- For merging two trees. -}
mergeTrees :: Ref -> Ref -> HashObjectHandle -> CatFileHandle -> Repo -> Streamer mergeTrees :: Ref -> Ref -> HashObjectHandle -> CatFileHandle -> Repo -> Streamer
mergeTrees (Ref x) (Ref y) hashhandle ch = doMerge hashhandle ch mergeTrees x y hashhandle ch = doMerge hashhandle ch
("diff-tree":diffOpts ++ [x, y, "--"]) ("diff-tree":diffOpts ++ [fromRef x, fromRef y, "--"])
{- For merging a single tree into the index. -} {- For merging a single tree into the index. -}
mergeTreeIndex :: Ref -> HashObjectHandle -> CatFileHandle -> Repo -> Streamer mergeTreeIndex :: Ref -> HashObjectHandle -> CatFileHandle -> Repo -> Streamer
mergeTreeIndex (Ref r) hashhandle ch = doMerge hashhandle ch $ mergeTreeIndex r hashhandle ch = doMerge hashhandle ch $
"diff-index" : diffOpts ++ ["--cached", r, "--"] "diff-index" : diffOpts ++ ["--cached", fromRef r, "--"]
diffOpts :: [String] diffOpts :: [String]
diffOpts = ["--raw", "-z", "-r", "--no-renames", "-l0"] diffOpts = ["--raw", "-z", "-r", "--no-renames", "-l0"]
@ -69,19 +71,19 @@ diffOpts = ["--raw", "-z", "-r", "--no-renames", "-l0"]
- using git to get a raw diff. -} - using git to get a raw diff. -}
doMerge :: HashObjectHandle -> CatFileHandle -> [String] -> Repo -> Streamer doMerge :: HashObjectHandle -> CatFileHandle -> [String] -> Repo -> Streamer
doMerge hashhandle ch differ repo streamer = do doMerge hashhandle ch differ repo streamer = do
(diff, cleanup) <- pipeNullSplit (map Param differ) repo (diff, cleanup) <- pipeNullSplit' (map Param differ) repo
go diff go diff
void $ cleanup void $ cleanup
where where
go [] = noop go [] = noop
go (info:file:rest) = mergeFile (decodeBL' info) (L.toStrict file) hashhandle ch >>= go (info:file:rest) = mergeFile info file hashhandle ch >>=
maybe (go rest) (\l -> streamer l >> go rest) maybe (go rest) (\l -> streamer l >> go rest)
go (_:[]) = error $ "parse error " ++ show differ go (_:[]) = error $ "parse error " ++ show differ
{- Given an info line from a git raw diff, and the filename, generates {- 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 - a line suitable for update-index that union merges the two sides of the
- diff. -} - diff. -}
mergeFile :: String -> RawFilePath -> HashObjectHandle -> CatFileHandle -> IO (Maybe L.ByteString) mergeFile :: S.ByteString -> RawFilePath -> HashObjectHandle -> CatFileHandle -> IO (Maybe L.ByteString)
mergeFile info file hashhandle h = case filter (`notElem` nullShas) [Ref asha, Ref bsha] of mergeFile info file hashhandle h = case filter (`notElem` nullShas) [Ref asha, Ref bsha] of
[] -> return Nothing [] -> return Nothing
(sha:[]) -> use sha (sha:[]) -> use sha
@ -89,7 +91,7 @@ mergeFile info file hashhandle h = case filter (`notElem` nullShas) [Ref asha, R
=<< either return (hashBlob hashhandle . L8.unlines) =<< either return (hashBlob hashhandle . L8.unlines)
=<< calcMerge . zip shas <$> mapM getcontents shas =<< calcMerge . zip shas <$> mapM getcontents shas
where where
[_colonmode, _bmode, asha, bsha, _status] = words info [_colonmode, _bmode, asha, bsha, _status] = S8.words info
use sha = return $ Just $ use sha = return $ Just $
updateIndexLine sha TreeFile $ asTopFilePath file updateIndexLine sha TreeFile $ asTopFilePath file
-- Get file and split into lines to union merge. -- Get file and split into lines to union merge.

View file

@ -75,14 +75,14 @@ lsTree (Ref x) repo streamer = do
mapM_ streamer s mapM_ streamer s
void $ cleanup void $ cleanup
where where
params = map Param ["ls-tree", "-z", "-r", "--full-tree", x] params = map Param ["ls-tree", "-z", "-r", "--full-tree", decodeBS' x]
lsSubTree :: Ref -> FilePath -> Repo -> Streamer lsSubTree :: Ref -> FilePath -> Repo -> Streamer
lsSubTree (Ref x) p repo streamer = do lsSubTree (Ref x) p repo streamer = do
(s, cleanup) <- pipeNullSplit params repo (s, cleanup) <- pipeNullSplit params repo
mapM_ streamer s mapM_ streamer s
void $ cleanup void $ cleanup
where where
params = map Param ["ls-tree", "-z", "-r", "--full-tree", x, p] params = map Param ["ls-tree", "-z", "-r", "--full-tree", decodeBS' x, p]
{- Generates a line suitable to be fed into update-index, to add {- Generates a line suitable to be fed into update-index, to add
- a given file with a given sha. -} - a given file with a given sha. -}
@ -90,7 +90,7 @@ updateIndexLine :: Sha -> TreeItemType -> TopFilePath -> L.ByteString
updateIndexLine sha treeitemtype file = L.fromStrict $ updateIndexLine sha treeitemtype file = L.fromStrict $
fmtTreeItemType treeitemtype fmtTreeItemType treeitemtype
<> " blob " <> " blob "
<> encodeBS (fromRef sha) <> fromRef' sha
<> "\t" <> "\t"
<> indexPath file <> indexPath file
@ -108,7 +108,7 @@ unstageFile file repo = do
unstageFile' :: TopFilePath -> Streamer unstageFile' :: TopFilePath -> Streamer
unstageFile' p = pureStreamer $ L.fromStrict $ unstageFile' p = pureStreamer $ L.fromStrict $
"0 " "0 "
<> encodeBS' (fromRef deleteSha) <> fromRef' deleteSha
<> "\t" <> "\t"
<> indexPath p <> indexPath p

View file

@ -158,12 +158,12 @@ buildExported exported = go (exportedTreeish exported : incompleteExportedTreeis
where where
go [] = mempty go [] = mempty
go (r:rs) = rref r <> mconcat [ charUtf8 ' ' <> rref r' | r' <- rs ] go (r:rs) = rref r <> mconcat [ charUtf8 ' ' <> rref r' | r' <- rs ]
rref r = byteString (encodeBS' (Git.fromRef r)) rref = byteString . Git.fromRef'
exportedParser :: A.Parser Exported exportedParser :: A.Parser Exported
exportedParser = Exported <$> refparser <*> many refparser exportedParser = Exported <$> refparser <*> many refparser
where where
refparser = (Git.Ref . decodeBS <$> A8.takeWhile1 (/= ' ') ) refparser = (Git.Ref <$> A8.takeWhile1 (/= ' ') )
<* ((const () <$> A8.char ' ') <|> A.endOfInput) <* ((const () <$> A8.char ' ') <|> A.endOfInput)
logExportExcluded :: UUID -> ((Git.Tree.TreeItem -> IO ()) -> Annex a) -> Annex a logExportExcluded :: UUID -> ((Git.Tree.TreeItem -> IO ()) -> Annex a) -> Annex a

View file

@ -43,7 +43,7 @@ readFsckResults u = do
deserialize ("truncated":ls) = deserialize' ls True deserialize ("truncated":ls) = deserialize' ls True
deserialize ls = deserialize' ls False deserialize ls = deserialize' ls False
deserialize' ls t = deserialize' ls t =
let s = S.fromList $ map Ref ls let s = S.fromList $ map (Ref . encodeBS') ls
in if S.null s then FsckFailed else FsckFoundMissing s t in if S.null s then FsckFailed else FsckFoundMissing s t
clearFsckResults :: UUID -> Annex () clearFsckResults :: UUID -> Annex ()

View file

@ -9,6 +9,8 @@
- Licensed under the GNU AGPL version 3 or higher. - Licensed under the GNU AGPL version 3 or higher.
-} -}
{-# LANGUAGE OverloadedStrings #-}
module Logs.View ( module Logs.View (
currentView, currentView,
setView, setView,
@ -31,6 +33,7 @@ import Logs.File
import qualified Data.Text as T import qualified Data.Text as T
import qualified Data.Set as S import qualified Data.Set as S
import Data.Char import Data.Char
import qualified Data.ByteString as B
setView :: View -> Annex () setView :: View -> Annex ()
setView v = do setView v = do
@ -54,11 +57,11 @@ recentViews = do
currentView :: Annex (Maybe View) currentView :: Annex (Maybe View)
currentView = go =<< inRepo Git.Branch.current currentView = go =<< inRepo Git.Branch.current
where where
go (Just b) | branchViewPrefix `isPrefixOf` fromRef b = go (Just b) | branchViewPrefix `B.isPrefixOf` fromRef' b =
headMaybe . filter (\v -> branchView v == b) <$> recentViews headMaybe . filter (\v -> branchView v == b) <$> recentViews
go _ = return Nothing go _ = return Nothing
branchViewPrefix :: String branchViewPrefix :: B.ByteString
branchViewPrefix = "refs/heads/views" branchViewPrefix = "refs/heads/views"
{- Generates a git branch name for a View. {- Generates a git branch name for a View.
@ -68,10 +71,11 @@ branchViewPrefix = "refs/heads/views"
-} -}
branchView :: View -> Git.Branch branchView :: View -> Git.Branch
branchView view branchView view
| null name = Git.Ref branchViewPrefix | B.null name = Git.Ref branchViewPrefix
| otherwise = Git.Ref $ branchViewPrefix ++ "/" ++ name | otherwise = Git.Ref $ branchViewPrefix <> "/" <> name
where where
name = intercalate ";" $ map branchcomp (viewComponents view) name = encodeBS' $
intercalate ";" $ map branchcomp (viewComponents view)
branchcomp c branchcomp c
| viewVisible c = branchcomp' c | viewVisible c = branchcomp' c
| otherwise = "(" ++ branchcomp' c ++ ")" | otherwise = "(" ++ branchcomp' c ++ ")"
@ -92,7 +96,7 @@ branchView view
is_branchView :: Git.Branch -> Bool is_branchView :: Git.Branch -> Bool
is_branchView (Ref b) is_branchView (Ref b)
| b == branchViewPrefix = True | b == branchViewPrefix = True
| otherwise = (branchViewPrefix ++ "/") `isPrefixOf` b | otherwise = (branchViewPrefix <> "/") `B.isPrefixOf` b
prop_branchView_legal :: View -> Bool prop_branchView_legal :: View -> Bool
prop_branchView_legal = Git.Ref.legal False . fromRef . branchView prop_branchView_legal = Git.Ref.legal False . fromRef . branchView

View file

@ -1664,7 +1664,7 @@ test_add_subdirs = intmpclonerepo $ do
unlessM (hasUnlockedFiles <$> getTestMode) $ do unlessM (hasUnlockedFiles <$> getTestMode) $ do
git_annex "sync" [] @? "sync failed" git_annex "sync" [] @? "sync failed"
l <- annexeval $ Utility.FileSystemEncoding.decodeBL l <- annexeval $ Utility.FileSystemEncoding.decodeBL
<$> Annex.CatFile.catObject (Git.Types.Ref "HEAD:dir/foo") <$> Annex.CatFile.catObject (Git.Types.Ref (encodeBS "HEAD:dir/foo"))
"../.git/annex/" `isPrefixOf` l @? ("symlink from subdir to .git/annex is wrong: " ++ l) "../.git/annex/" `isPrefixOf` l @? ("symlink from subdir to .git/annex is wrong: " ++ l)
createDirectory "dir2" createDirectory "dir2"

View file

@ -343,7 +343,7 @@ extractRemoteGitConfig r remotename = do
, remoteAnnexReadOnly = getbool "readonly" False , remoteAnnexReadOnly = getbool "readonly" False
, remoteAnnexCheckUUID = getbool "checkuuid" True , remoteAnnexCheckUUID = getbool "checkuuid" True
, remoteAnnexVerify = getbool "verify" True , remoteAnnexVerify = getbool "verify" True
, remoteAnnexTrackingBranch = Git.Ref <$> , remoteAnnexTrackingBranch = Git.Ref . encodeBS <$>
( notempty (getmaybe "tracking-branch") ( notempty (getmaybe "tracking-branch")
<|> notempty (getmaybe "export-tracking") -- old name <|> notempty (getmaybe "export-tracking") -- old name
) )

View file

@ -32,7 +32,7 @@ parseRefSpec v = case partitionEithers (map mk $ splitc ':' v) of
mk ('+':s) mk ('+':s)
| any (`elem` s) "*?" = | any (`elem` s) "*?" =
Right $ AddMatching $ compileGlob s CaseSensative Right $ AddMatching $ compileGlob s CaseSensative
| otherwise = Right $ AddRef $ Ref s | otherwise = Right $ AddRef $ Ref $ encodeBS s
mk ('-':s) = Right $ RemoveMatching $ compileGlob s CaseSensative mk ('-':s) = Right $ RemoveMatching $ compileGlob s CaseSensative
mk "reflog" = Right AddRefLog mk "reflog" = Right AddRefLog
mk s = Left $ "bad refspec item \"" ++ s ++ "\" (expected + or - prefix)" mk s = Left $ "bad refspec item \"" ++ s ++ "\" (expected + or - prefix)"

View file

@ -5,6 +5,8 @@
- Licensed under the GNU AGPL version 3 or higher. - Licensed under the GNU AGPL version 3 or higher.
-} -}
{-# LANGUAGE OverloadedStrings #-}
module Types.View where module Types.View where
import Annex.Common import Annex.Common

View file

@ -92,7 +92,8 @@ logFiles dir = return . filter (".log" `isSuffixOf`)
push :: Annex () push :: Annex ()
push = do push = do
origin_master <- inRepo $ Git.Ref.exists $ Git.Ref "origin/master" origin_master <- inRepo $ Git.Ref.exists $
Git.Ref $ encodeBS' "origin/master"
origin_gitannex <- Annex.Branch.hasOrigin origin_gitannex <- Annex.Branch.hasOrigin
case (origin_master, origin_gitannex) of case (origin_master, origin_gitannex) of
(_, True) -> do (_, True) -> do

View file

@ -59,7 +59,7 @@ setIndirect = do
fromDirectBranch :: Ref -> Ref fromDirectBranch :: Ref -> Ref
fromDirectBranch directhead = case splitc '/' $ fromRef directhead of fromDirectBranch directhead = case splitc '/' $ fromRef directhead of
("refs":"heads":"annex":"direct":rest) -> ("refs":"heads":"annex":"direct":rest) ->
Ref $ "refs/heads/" ++ intercalate "/" rest Ref $ encodeBS' $ "refs/heads/" ++ intercalate "/" rest
_ -> directhead _ -> directhead
switchHEADBack :: Annex () switchHEADBack :: Annex ()

View file

@ -11,6 +11,7 @@ module Utility.Misc (
hGetContentsStrict, hGetContentsStrict,
readFileStrict, readFileStrict,
separate, separate,
separate',
firstLine, firstLine,
firstLine', firstLine',
segment, segment,
@ -54,6 +55,13 @@ separate c l = unbreak $ break c l
| null b = r | null b = r
| otherwise = (a, tail b) | otherwise = (a, tail b)
separate' :: (Word8 -> Bool) -> S.ByteString -> (S.ByteString, S.ByteString)
separate' c l = unbreak $ S.break c l
where
unbreak r@(a, b)
| S.null b = r
| otherwise = (a, S.tail b)
{- Breaks out the first line. -} {- Breaks out the first line. -}
firstLine :: String -> String firstLine :: String -> String
firstLine = takeWhile (/= '\n') firstLine = takeWhile (/= '\n')

View file

@ -1,7 +1,7 @@
{- System.Process enhancements, including additional ways of running {- System.Process enhancements, including additional ways of running
- processes, and logging. - processes, and logging.
- -
- Copyright 2012-2015 Joey Hess <id@joeyh.name> - Copyright 2012-2020 Joey Hess <id@joeyh.name>
- -
- License: BSD-2-clause - License: BSD-2-clause
-} -}
@ -53,6 +53,7 @@ import System.Log.Logger
import Control.Concurrent import Control.Concurrent
import qualified Control.Exception as E import qualified Control.Exception as E
import Control.Monad import Control.Monad
import qualified Data.ByteString as S
type CreateProcessRunner = forall a. CreateProcess -> ((Maybe Handle, Maybe Handle, Maybe Handle, ProcessHandle) -> IO a) -> IO a type CreateProcessRunner = forall a. CreateProcess -> ((Maybe Handle, Maybe Handle, Maybe Handle, ProcessHandle) -> IO a) -> IO a
@ -85,25 +86,20 @@ writeReadProcessEnv
-> [String] -> [String]
-> Maybe [(String, String)] -> Maybe [(String, String)]
-> (Maybe (Handle -> IO ())) -> (Maybe (Handle -> IO ()))
-> (Maybe (Handle -> IO ())) -> IO S.ByteString
-> IO String writeReadProcessEnv cmd args environ writestdin = do
writeReadProcessEnv cmd args environ writestdin adjusthandle = do
(Just inh, Just outh, _, pid) <- createProcess p (Just inh, Just outh, _, pid) <- createProcess p
maybe (return ()) (\a -> a inh) adjusthandle
maybe (return ()) (\a -> a outh) adjusthandle
-- fork off a thread to start consuming the output -- fork off a thread to start consuming the output
output <- hGetContents outh
outMVar <- newEmptyMVar outMVar <- newEmptyMVar
_ <- forkIO $ E.evaluate (length output) >> putMVar outMVar () _ <- forkIO $ putMVar outMVar =<< S.hGetContents outh
-- now write and flush any input -- now write and flush any input
maybe (return ()) (\a -> a inh >> hFlush inh) writestdin maybe (return ()) (\a -> a inh >> hFlush inh) writestdin
hClose inh -- done with stdin hClose inh -- done with stdin
-- wait on the output -- wait on the output
takeMVar outMVar output <- takeMVar outMVar
hClose outh hClose outh
-- wait on the process -- wait on the process

View file

@ -3,3 +3,9 @@ to contain a ByteString, rather than a String, would eliminate a
fromRawFilePath that uses about 1% of runtime. fromRawFilePath that uses about 1% of runtime.
[[!tag confirmed]] [[!tag confirmed]]
> Well, I did the conversion. Running that command does not seem to have
> sped up by any appreciable amount. But, I did notice several places where
> using ByteString is certainly more efficient. It may just be that it
> doesn't matter if git-annex is IO bound etc. Still, glad I did it.
> [[done]] --[[Joey]]