Implement loading a commit graph

This commit is contained in:
fr33domlover 2016-02-29 21:42:37 +00:00
parent 4882ddb092
commit 7a76703d25
2 changed files with 49 additions and 5 deletions

View file

@ -15,18 +15,27 @@
-- | Git repo tools using the @hit@ package. -- | Git repo tools using the @hit@ package.
module Data.Git.Local module Data.Git.Local
( ( loadCommits
, loadCommitGraphByRef
) )
where where
import Prelude import Prelude
import Control.Monad.IO.Class import Control.Monad.IO.Class
import Data.Foldable (foldlM) import Data.Foldable (foldl', foldlM)
import Data.Git.Ref (Ref) import Data.Git.Ref (Ref, toBinary)
import Data.Git.Repository (getCommit) import Data.Git.Repository (getCommit)
import Data.Git.Storage (Git) import Data.Git.Storage (Git)
import Data.Git.Types (Commit (..)) import Data.Git.Types (Commit (..))
import Data.Graph.Inductive.Graph (Graph (mkGraph))
import Data.Hashable (Hashable (..))
import qualified Data.HashMap.Strict as M
instance Hashable Ref where
hashWithSalt salt = hashWithSalt salt . toBinary
hash = hash . toBinary
-- | Load the entire graph of commits which are ancestors of the given ref -- | Load the entire graph of commits which are ancestors of the given ref
-- (and that ref itself). Fold the commit structure into a value of type @a@ -- (and that ref itself). Fold the commit structure into a value of type @a@
@ -52,10 +61,15 @@ loadCommits
-- ^ Initial value -- ^ Initial value
-> Ref -> Ref
-- ^ Hash of the commit whose ancestor graph should be loaded -- ^ Hash of the commit whose ancestor graph should be loaded
-> Maybe Commit
-- ^ If you already read the commit for the ref passed as the previous
-- parameter, pass the commit here to avoid repeated loading of it.
-- Otherwise, pass 'Nothing' and it will be read from the repo.
-> m a -> m a
loadCommits git func val ref = readCommit ref >>= go val ref loadCommits git func val ref mcmt = readCommitMaybe ref mcmt >>= go val ref
where where
readCommit = liftIO . getCommit git readCommit = liftIO . getCommit git
readCommitMaybe r = maybe (readCommit r) return
--readRefCommit r = do --readRefCommit r = do
-- c <- readCommit r -- c <- readCommit r
-- return (r, c) -- return (r, c)
@ -68,3 +82,32 @@ loadCommits git func val ref = readCommit ref >>= go val ref
--let rs = commitParents c --let rs = commitParents c
--ps <- mapM readRefCommit rs --ps <- mapM readRefCommit rs
--foldlM (step (r, c)) v rs --foldlM (step (r, c)) v rs
type NodeLabel = (Ref, Commit)
type EdgeLabel = ()
type CommitGraph g = g NodeLabel EdgeLabel
-- | Use 'loadCommits' to build a directed acyclic graph of commits. There is a
-- single root node, which is the ref passed to this function.
loadCommitGraphByRef :: Graph g => Git -> Ref -> IO (CommitGraph g)
loadCommitGraphByRef git ref = do
let rootN = 1
visit (_rChild, _cChild) rParent v@(nextNode, commits) =
if rParent `M.member` commits
then return (v, Nothing)
else do
cParent <- getCommit git rParent
let commits' = M.insert rParent (cParent, nextNode) commits
return ((nextNode + 1, commits'), Just cParent)
cmt <- getCommit git ref
(_, commits) <- loadCommits git visit (rootN + 1, M.empty) ref (Just cmt)
let commits' = M.insert ref (cmt, rootN) commits
nodeOf r = maybe (error "ref has no node") snd $ M.lookup r commits'
mkNode l r (c, n) = (n, (r, c)) : l
nodes = M.foldlWithKey' mkNode [] commits'
mkEdge n l r = (n, nodeOf r, ()) : l
mkEdges l (c, n) = foldl' (mkEdge n) l $ commitParents c
edges = M.foldl' mkEdges [] commits'
return $ mkGraph nodes edges

View file

@ -102,6 +102,7 @@ library
, fgl , fgl
, file-embed , file-embed
, filepath , filepath
, hashable
, hit , hit
, hjsmin >= 0.1 && < 0.2 , hjsmin >= 0.1 && < 0.2
, hourglass , hourglass
@ -119,7 +120,7 @@ library
, time , time
, transformers , transformers
, unordered-containers , unordered-containers
, vector --, vector
, wai , wai
, wai-extra >= 3.0 && < 3.1 , wai-extra >= 3.0 && < 3.1
, wai-logger >= 2.2 && < 2.3 , wai-logger >= 2.2 && < 2.3