diff options
author | Joey Hess <joeyh@joeyh.name> | 2016-02-25 14:59:35 -0400 |
---|---|---|
committer | Joey Hess <joeyh@joeyh.name> | 2016-02-25 15:14:47 -0400 |
commit | 063e26fb58d6f835b9325e280f322eb5788ca660 (patch) | |
tree | 433d5bbabf0eeba0ab0e2afd8c9a7994bdb5863d /Git | |
parent | c5df5fd4fa172782fee20f966b04c3793df140a1 (diff) |
add catCommit, with commit object parser
Diffstat (limited to 'Git')
-rw-r--r-- | Git/CatFile.hs | 47 | ||||
-rw-r--r-- | Git/Env.hs | 16 | ||||
-rw-r--r-- | Git/Types.hs | 15 |
3 files changed, 77 insertions, 1 deletions
diff --git a/Git/CatFile.hs b/Git/CatFile.hs index d213bef06..455f192a0 100644 --- a/Git/CatFile.hs +++ b/Git/CatFile.hs @@ -1,6 +1,6 @@ {- git cat-file interface - - - Copyright 2011, 2013 Joey Hess <id@joeyh.name> + - Copyright 2011-2016 Joey Hess <id@joeyh.name> - - Licensed under the GNU GPL version 3 or higher. -} @@ -13,6 +13,7 @@ module Git.CatFile ( catFile, catFileDetails, catTree, + catCommit, catObject, catObjectDetails, ) where @@ -20,6 +21,10 @@ module Git.CatFile ( import System.IO import qualified Data.ByteString as S import qualified Data.ByteString.Lazy as L +import qualified Data.ByteString.Lazy.Char8 as L8 +import qualified Data.Map as M +import Data.String +import Data.Char import Data.Tuple.Utils import Numeric import System.Posix.Types @@ -110,3 +115,43 @@ catTree h treeref = go <$> catObjectDetails h treeref let (modestr, file) = separate (== ' ') (decodeBS b) in (file, readmode modestr) readmode = fromMaybe 0 . fmap fst . headMaybe . readOct + +catCommit :: CatFileHandle -> Ref -> IO (Maybe Commit) +catCommit h commitref = go <$> catObjectDetails h commitref + where + go (Just (b, _, CommitObject)) = parseCommit b + go _ = Nothing + +parseCommit :: L.ByteString -> Maybe Commit +parseCommit b = Commit + <$> (extractSha . L8.unpack =<< field "tree") + <*> (parsemetadata <$> field "author") + <*> (parsemetadata <$> field "committer") + <*> Just (L8.unpack $ L.intercalate (L.singleton nl) message) + where + field n = M.lookup (fromString n) fields + fields = M.fromList ((map breakfield) header) + breakfield l = + let (k, sp_v) = L.break (== sp) l + in (k, L.drop 1 sp_v) + (header, message) = separate L.null ls + ls = L.split nl b + + -- author and committer lines have the form: "name <email> date" + -- The email is always present, even if empty "<>" + parsemetadata l = CommitMetaData + { commitName = whenset $ L.init name_sp + , commitEmail = whenset email + , commitDate = whenset $ L.drop 2 gt_sp_date + } + where + (name_sp, rest) = L.break (== lt) l + (email, gt_sp_date) = L.break (== gt) (L.drop 1 rest) + whenset v + | L.null v = Nothing + | otherwise = Just (L8.unpack v) + + nl = fromIntegral (ord '\n') + sp = fromIntegral (ord ' ') + lt = fromIntegral (ord '<') + gt = fromIntegral (ord '>') diff --git a/Git/Env.hs b/Git/Env.hs index 35a4eb04d..0173513a7 100644 --- a/Git/Env.hs +++ b/Git/Env.hs @@ -10,6 +10,7 @@ module Git.Env where import Git +import Git.Types import Utility.Env {- Adjusts the gitEnv of a Repo. Copies the system environment if the repo @@ -36,3 +37,18 @@ adjustGitEnv g adj = do addGitEnv :: Repo -> String -> String -> IO Repo addGitEnv g var val = adjustGitEnv g (addEntry var val) + +{- Use with any action that makes a commit to set metadata. -} +commitWithMetaData :: CommitMetaData -> CommitMetaData -> (Repo -> IO a) -> Repo -> IO a +commitWithMetaData authormetadata committermetadata a g = + a =<< adjustGitEnv g adj + where + adj = mkadj "AUTHOR" authormetadata + . mkadj "COMMITTER" committermetadata + mkadj p md = go "NAME" commitName + . go "EMAIL" commitEmail + . go "DATE" commitDate + where + go s getv = case getv md of + Nothing -> id + Just v -> addEntry ("GIT_" ++ p ++ "_" ++ s) v diff --git a/Git/Types.hs b/Git/Types.hs index 1eef2f743..e694c2072 100644 --- a/Git/Types.hs +++ b/Git/Types.hs @@ -97,3 +97,18 @@ toBlobType 0o100644 = Just FileBlob toBlobType 0o100755 = Just ExecutableBlob toBlobType 0o120000 = Just SymlinkBlob toBlobType _ = Nothing + +data Commit = Commit + { commitTree :: Sha + , commitAuthorMetaData :: CommitMetaData + , commitCommitterMetaData :: CommitMetaData + , commitMessage :: String + } + deriving (Show) + +data CommitMetaData = CommitMetaData + { commitName :: Maybe String + , commitEmail :: Maybe String + , commitDate :: Maybe String -- In raw git form, "epoch -tzoffset" + } + deriving (Show) |