@@ -30,50 +30,39 @@ clone url path = sh $ do
3030-- | git cat-file -p
3131catFile :: FilePath -> OID -> IO Text
3232catFile gitDir (OID oid) = sh $ do
33- run " git" [pack ( " --git-dir= " <> gitDir) , " cat-file" , " -p" , oid]
33+ run " git" [" -C " , pack gitDir, " cat-file" , " -p" , oid]
3434
3535-- | git ls-tree -rz
3636lsTree :: FilePath -> OID -> IO [TreeEntry ]
37- lsTree gitDir (OID sha) = sh $ do
38- out <- run " git" [pack (" --git-dir=" <> gitDir), " ls-tree" , " -rz" , sha]
39- pure $ parseEntries out
37+ lsTree gitDir (OID sha) = sh $ parseEntries <$> run " git" [" -C" , pack gitDir, " ls-tree" , " -rz" , sha]
4038
4139sh :: MonadIO m => Sh a -> m a
4240sh = shelly . silently . onCommandHandles (initOutputHandles (`hSetBinaryMode` True ))
4341
4442-- | Parses an list of entries separated by \NUL, and on failure return []
4543parseEntries :: Text -> [TreeEntry ]
46- parseEntries = either (const [] ) id . AP. parseOnly (AP. sepBy entryParser (AP. char ' \NUL ' ))
44+ parseEntries text = case parseOnly everything text of
45+ Done " " ls -> ls
46+ other -> error (" There was an error parsing the Git output: " <> show other)
47+ where
48+ everything = AP. sepBy entryParser " \NUL " <* (" \NUL\n " <?> " End sequence" ) <* AP. endOfInput <?> " Everything"
49+ parseOnly p t = AP. feed (AP. parse p t) " "
4750
4851-- | Parse the entire input with entryParser, and on failure return a default
4952-- For testing purposes only
5053parseEntry :: Text -> TreeEntry
51- parseEntry = either (const nullTreeEntry) id . AP. parseOnly entryParser
54+ parseEntry = either (const nullTreeEntry) id . AP. parseOnly ( entryParser <* AP. endOfInput)
5255
53- -- | Parses an entry successfully, falling back to the failure case if necessary.
56+ -- | Parses a TreeEntry
5457entryParser :: Parser TreeEntry
55- entryParser = AP. choice [entrySuccessParser, entryDefaultParser]
56-
57- -- | Attoparsec parser for a block af text ending with \NUL
58- -- in order to consume invalid input
59- entryDefaultParser :: Parser TreeEntry
60- entryDefaultParser = do
61- _ <- AP. takeWhile (/= ' \NUL ' )
62- pure $ nullTreeEntry
63-
64- -- | Attoparsec parser for a single line of git ls-tree -rz output
65- entrySuccessParser :: Parser TreeEntry
66- entrySuccessParser = do
67- mode <- takeWhileToNul (/= ' ' )
68- _ <- AP. char ' '
69- ty <- takeWhileToNul (/= ' ' )
70- _ <- AP. char ' '
71- oid <- takeWhileToNul (/= ' \t ' )
72- _ <- AP. char ' \t '
73- path <- takeWhileToNul (const True )
74- pure $ TreeEntry (objectMode mode) (objectType ty) (OID oid) (unpack path)
58+ entryParser = TreeEntry
59+ <$> modeParser <* (" " <?> " First Space" )
60+ <*> typeParser <* (" " <?> " Second Space" )
61+ <*> (OID <$> AP. takeWhile (AP. inClass " 0123456789abcdef" ) <?> " OID Parser" ) <* (" \t " <?> " Tab" )
62+ <*> (unpack <$> AP. takeWhile (/= ' \NUL ' ) <?> " Filepath" ) <?> " Entry Parser"
7563 where
76- takeWhileToNul f = AP. takeWhile (\ x -> f x && x /= ' \NUL ' )
64+ typeParser = AP. choice [BlobObject <$ " blob" , TreeObject <$ " tree" ] <?> " Type Parser"
65+ modeParser = AP. choice [NormalMode <$ " 100644" , ExecutableMode <$ " 100755" , SymlinkMode <$ " 120000" , TreeMode <$ " 040000" ] <?> " Mode Parser"
7766
7867newtype OID = OID Text
7968 deriving (Eq , Show , Ord )
@@ -86,24 +75,12 @@ data ObjectMode
8675 | OtherMode
8776 deriving (Eq , Show )
8877
89- objectMode :: Text -> ObjectMode
90- objectMode " 100644" = NormalMode
91- objectMode " 100755" = ExecutableMode
92- objectMode " 120000" = SymlinkMode
93- objectMode " 040000" = TreeMode
94- objectMode _ = OtherMode
95-
9678data ObjectType
9779 = BlobObject
9880 | TreeObject
9981 | OtherObjectType
10082 deriving (Eq , Show )
10183
102- objectType :: Text -> ObjectType
103- objectType " blob" = BlobObject
104- objectType " tree" = TreeObject
105- objectType _ = OtherObjectType
106-
10784data TreeEntry
10885 = TreeEntry
10986 { treeEntryMode :: ObjectMode
0 commit comments