summaryrefslogtreecommitdiff
path: root/Git/LsTree.hs
diff options
context:
space:
mode:
authorJoey Hess <joeyh@joeyh.name>2020-01-02 12:34:10 -0400
committerJoey Hess <joeyh@joeyh.name>2020-01-02 12:42:57 -0400
commit9df8a6eb9405dde4464d27133c04f5ee539a85de (patch)
tree8a7ac5f52be8679f8a2525515a0b2c1b715c99ad /Git/LsTree.hs
parent16022a8b98f4bc134542e78a42538364d2f97d92 (diff)
downloadgit-repair-9df8a6eb9405dde4464d27133c04f5ee539a85de.tar.gz
merge from git-annex and relicense accordingly
Merge git library and utility from git-annex. The former is now relicensed AGPL, so git-repair as a whole becomes AGPL. For simplicity, I am relicensing the remainder of the code in git-repair AGPL as well, per the header changes in this commit. While that code is also technically available under the GPL license, as it's been released under that license before, changes going forward will be only released by me under the AGPL.
Diffstat (limited to 'Git/LsTree.hs')
-rw-r--r--Git/LsTree.hs85
1 files changed, 55 insertions, 30 deletions
diff --git a/Git/LsTree.hs b/Git/LsTree.hs
index 225f2ce..a3d8383 100644
--- a/Git/LsTree.hs
+++ b/Git/LsTree.hs
@@ -1,19 +1,21 @@
{- git ls-tree interface
-
- - Copyright 2011-2016 Joey Hess <id@joeyh.name>
+ - Copyright 2011-2019 Joey Hess <id@joeyh.name>
-
- - Licensed under the GNU GPL version 3 or higher.
+ - Licensed under the GNU AGPL version 3 or higher.
-}
{-# LANGUAGE BangPatterns #-}
module Git.LsTree (
TreeItem(..),
+ LsTreeMode(..),
lsTree,
lsTree',
lsTreeParams,
lsTreeFiles,
parseLsTree,
+ formatLsTree,
) where
import Common
@@ -22,42 +24,52 @@ import Git.Command
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
-{- Lists the complete contents of a tree, recursing into sub-trees,
- - with lazy output. -}
-lsTree :: Ref -> Repo -> IO ([TreeItem], IO Bool)
+data LsTreeMode = LsTreeRecursive | LsTreeNonRecursive
+
+{- Lists the contents of a tree, with lazy output. -}
+lsTree :: LsTreeMode -> Ref -> Repo -> IO ([TreeItem], IO Bool)
lsTree = lsTree' []
-lsTree' :: [CommandParam] -> Ref -> Repo -> IO ([TreeItem], IO Bool)
-lsTree' ps t repo = do
- (l, cleanup) <- pipeNullSplit (lsTreeParams t ps) repo
- return (map parseLsTree l, cleanup)
+lsTree' :: [CommandParam] -> LsTreeMode -> Ref -> Repo -> IO ([TreeItem], IO Bool)
+lsTree' ps lsmode t repo = do
+ (l, cleanup) <- pipeNullSplit (lsTreeParams lsmode t ps) repo
+ return (rights (map parseLsTree l), cleanup)
-lsTreeParams :: Ref -> [CommandParam] -> [CommandParam]
-lsTreeParams r ps =
+lsTreeParams :: LsTreeMode -> Ref -> [CommandParam] -> [CommandParam]
+lsTreeParams lsmode r ps =
[ Param "ls-tree"
, Param "--full-tree"
, Param "-z"
- , Param "-r"
- ] ++ ps ++
+ ] ++ recursiveparams ++ ps ++
[ Param "--"
, File $ fromRef r
]
+ where
+ recursiveparams = case lsmode of
+ LsTreeRecursive -> [ Param "-r" ]
+ LsTreeNonRecursive -> []
{- 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"
@@ -67,21 +79,34 @@ lsTreeFiles t fs repo = map parseLsTree <$> pipeNullSplitStrict ps repo
, 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) ""
+ , decodeBS (typeobj ti)
+ , fromRef (sha ti)
+ , fromRawFilePath (getTopFilePath (file ti))
+ ]