packages feed

gitlib 1.2.1 → 1.3.1

raw patch · 2 files changed

+659/−146 lines, 2 filesdep +base16-bytestringdep +binarydep +hashablePVP ok

version bump matches the API change (PVP)

Dependencies added: base16-bytestring, binary, hashable, system-fileio, unordered-containers

API changes (from Hackage documentation)

- Git: allRefNames :: Repository m => m [Text]
- Git: allRefs :: Repository m => m [Reference m (Commit m)]
- Git: cloneTree :: Repository m => RepositoryTree m -> m (RepositoryTree m)
- Git: commitEntryRef :: TreeEntry m -> !(CommitOid m)
- Git: createRef :: Repository m => Text -> RefTarget m (Commit m) -> m (Reference m (Commit m))
- Git: createRef_ :: Repository m => Text -> RefTarget m (Commit m) -> m ()
- Git: data MutableTree
- Git: data PersistentTree
- Git: deleteRef :: Repository m => Text -> m ()
- Git: instance (Functor m, Monad m) => Applicative (TreeT t m)
- Git: instance (Functor m, MonadPlus m) => Alternative (TreeT t m)
- Git: instance Functor m => Functor (TreeT t m)
- Git: instance Monad m => Monad (TreeT t m)
- Git: instance MonadFix m => MonadFix (TreeT t m)
- Git: instance MonadIO m => MonadIO (TreeT t m)
- Git: instance MonadPlus m => MonadPlus (TreeT t m)
- Git: instance MonadTrans (TreeT t)
- Git: lookupRef :: Repository m => Text -> m (Maybe (Reference m (Commit m)))
- Git: newTree :: Repository m => m (RepositoryTree m)
- Git: refName :: Reference m a -> !Text
- Git: refTarget :: Reference m a -> !(RefTarget m a)
- Git: resolveRef :: Repository m => Text -> m (Maybe (CommitRef m))
- Git: treeEntryRef :: TreeEntry m -> !(TreeRef m)
- Git: type MutableTreeT m a = TreeT (Tree m MutableTree) m a
- Git: type PersistentTreeT m a = TreeT (Tree m PersistentTree) m a
- Git: type RepositoryTree m = Tree m (TreeKind m)
- Git: type RepositoryTreeT m a = TreeT (RepositoryTree m) m a
- Git: unsafeGetTree :: Monad m => RepositoryTreeT m (RepositoryTree m)
- Git: unsafeMutateTree :: Repository m => Tree m MutableTree -> MutableTreeT m a -> m (Tree m MutableTree)
- Git: unsafeMutateTree_ :: Repository m => Tree m MutableTree -> MutableTreeT m a -> m ()
- Git: unsafePutTree :: Monad m => RepositoryTree m -> RepositoryTreeT m ()
- Git: unsafeUpdateTree :: Repository m => RepositoryTree m -> FilePath -> Bool -> (Maybe (TreeEntry m) -> ModifyTreeResult m) -> m (RepositoryTree m, Maybe (TreeEntry m))
- Git: unsafeWithTree :: Repository m => Tree m MutableTree -> MutableTreeT m a -> m (a, Tree m MutableTree)
- Git: updateRef :: Repository m => Text -> RefTarget m (Commit m) -> m (Reference m (Commit m))
- Git: updateRef_ :: Repository m => Text -> RefTarget m (Commit m) -> m ()
- Git: writeTree :: Repository m => RepositoryTree m -> m (TreeOid m)
+ Git: BuilderUnchanged :: (TreeBuilder m) -> ModifiedBuilder m
+ Git: ModifiedBuilder :: (TreeBuilder m) -> ModifiedBuilder m
+ Git: PinnedEntry :: Oid m -> Commit m -> TreeEntry m -> PinnedEntry m
+ Git: SHA :: ByteString -> SHA
+ Git: TreeBuilder :: Maybe (TreeRef m) -> HashMap Text (TreeBuilder m) -> (Maybe (Tree m) -> m (TreeBuilder m)) -> (TreeBuilder m -> m (ModifiedBuilder m, TreeRef m)) -> (Text -> m (Maybe (TreeEntry m))) -> m Int -> (TreeBuilder m -> Text -> TreeEntry m -> m (ModifiedBuilder m)) -> (TreeBuilder m -> Text -> m (ModifiedBuilder m)) -> TreeBuilder m
+ Git: allMissingObjects :: Repository m => [Object m] -> m [Object m]
+ Git: allReferenceNames :: Repository m => m [Text]
+ Git: allReferences :: Repository m => m [Reference m (Commit m)]
+ Git: blobContentsToByteString :: Repository m => BlobContents m -> m ByteString
+ Git: blobToByteString :: Repository m => Blob m -> m ByteString
+ Git: catBlob :: Repository m => Text -> m ByteString
+ Git: catBlobUtf8 :: Repository m => Text -> m Text
+ Git: commitEntryHistory :: Repository m => Commit m -> FilePath -> m [PinnedEntry m]
+ Git: commitEntryOid :: TreeEntry m -> !(CommitOid m)
+ Git: commitHistoryFirstParent :: Repository m => Commit m -> m [Commit m]
+ Git: commitTreeEntry :: Repository m => Commit m -> FilePath -> m (Maybe (TreeEntry m))
+ Git: copyBlob :: (Repository m, Repository (t m), MonadTrans t) => BlobRef m -> HashSet Text -> t m (BlobOid (t m), HashSet Text)
+ Git: copyCommit :: (Repository m, Repository (t m), MonadTrans t) => CommitRef m -> Maybe Text -> HashSet Text -> t m (CommitRef (t m), HashSet Text)
+ Git: copyTree :: (Repository m, Repository (t m), MonadTrans t) => TreeRef m -> HashSet Text -> t m (TreeRef (t m), HashSet Text)
+ Git: copyTreeEntry :: (Repository m, Repository (t m), MonadTrans t) => TreeEntry m -> HashSet Text -> t m (TreeEntry (t m), HashSet Text)
+ Git: createBlobUtf8 :: Repository m => Text -> m (BlobOid m)
+ Git: createReference :: Repository m => Text -> RefTarget m (Commit m) -> m (Reference m (Commit m))
+ Git: createReference_ :: Repository m => Text -> RefTarget m (Commit m) -> m ()
+ Git: currentTree :: Repository m => TreeT m (Tree m)
+ Git: currentTreeRef :: Repository m => TreeT m (TreeRef m)
+ Git: data ModifiedBuilder m
+ Git: data PinnedEntry m
+ Git: data TreeBuilder m
+ Git: deleteReference :: Repository m => Text -> m ()
+ Git: emptyTreeId :: Text
+ Git: genericPushCommit :: (Repository m, Repository (t m), MonadTrans t) => CommitName m -> Text -> t m (CommitRef (t m))
+ Git: getCommitParents :: Repository m => Commit m -> m [Commit m]
+ Git: getTreeEntryOid :: Repository m => TreeEntry m -> Oid m
+ Git: identifyEntry :: Repository m => Commit m -> TreeEntry m -> m (PinnedEntry m)
+ Git: instance (Functor m, Monad m) => Applicative (TreeT m)
+ Git: instance (Functor m, MonadPlus m) => Alternative (TreeT m)
+ Git: instance Binary SHA
+ Git: instance Eq BuilderAction
+ Git: instance Eq SHA
+ Git: instance Functor m => Functor (TreeT m)
+ Git: instance Hashable SHA
+ Git: instance IsOid SHA
+ Git: instance Monad m => Monad (TreeT m)
+ Git: instance Monad m => Monoid (TreeBuilder m)
+ Git: instance MonadFix m => MonadFix (TreeT m)
+ Git: instance MonadIO m => MonadIO (TreeT m)
+ Git: instance MonadPlus m => MonadPlus (TreeT m)
+ Git: instance MonadTrans TreeT
+ Git: instance Monoid (ModifiedBuilder m)
+ Git: instance Ord SHA
+ Git: instance Read SHA
+ Git: instance Show BuilderAction
+ Git: instance Show SHA
+ Git: lookupReference :: Repository m => Text -> m (Maybe (Reference m (Commit m)))
+ Git: mtbBaseTreeRef :: TreeBuilder m -> Maybe (TreeRef m)
+ Git: mtbDropEntry :: TreeBuilder m -> TreeBuilder m -> Text -> m (ModifiedBuilder m)
+ Git: mtbEntryCount :: TreeBuilder m -> m Int
+ Git: mtbLookupEntry :: TreeBuilder m -> Text -> m (Maybe (TreeEntry m))
+ Git: mtbNewBuilder :: TreeBuilder m -> Maybe (Tree m) -> m (TreeBuilder m)
+ Git: mtbPendingUpdates :: TreeBuilder m -> HashMap Text (TreeBuilder m)
+ Git: mtbPutEntry :: TreeBuilder m -> TreeBuilder m -> Text -> TreeEntry m -> m (ModifiedBuilder m)
+ Git: mtbWriteContents :: TreeBuilder m -> TreeBuilder m -> m (ModifiedBuilder m, TreeRef m)
+ Git: mutateTreeRef :: Repository m => TreeRef m -> TreeT m a -> m (TreeRef m)
+ Git: newTreeBuilder :: Repository m => Maybe (Tree m) -> m (TreeBuilder m)
+ Git: newtype SHA
+ Git: pinnedCommit :: PinnedEntry m -> Commit m
+ Git: pinnedEntry :: PinnedEntry m -> TreeEntry m
+ Git: pinnedOid :: PinnedEntry m -> Oid m
+ Git: referenceName :: Reference m a -> !Text
+ Git: referenceTarget :: Reference m a -> !(RefTarget m a)
+ Git: resolveReference :: Repository m => Text -> m (Maybe (CommitRef m))
+ Git: resolveReferenceTree :: Repository m => Text -> m (Maybe (Tree m))
+ Git: shaToText :: SHA -> Text
+ Git: textToSha :: Monad m => Text -> m SHA
+ Git: treeBlobEntries :: Repository m => Tree m -> m [(FilePath, TreeEntry m)]
+ Git: treeOid :: Repository m => Tree m -> TreeOid m
+ Git: updateReference :: Repository m => Text -> RefTarget m (Commit m) -> m (Reference m (Commit m))
+ Git: updateReference_ :: Repository m => Text -> RefTarget m (Commit m) -> m ()
+ Git: withNewRepository :: (Repository (t m), MonadGit (t m), MonadBaseControl IO m, MonadIO m, MonadTrans t) => RepositoryFactory t m c -> FilePath -> t m a -> m a
+ Git: withNewRepository' :: (Repository (t m), MonadGit (t m), MonadBaseControl IO m, MonadIO m, MonadTrans t) => RepositoryFactory t m c -> FilePath -> t m a -> m a
+ Git: withTreeRef :: Repository m => TreeRef m -> TreeT m a -> m (a, TreeRef m)
- Git: TreeEntry :: !(TreeRef m) -> TreeEntry m
+ Git: TreeEntry :: !(TreeOid m) -> TreeEntry m
- Git: class (Eq o, Ord o, Show o) => IsOid o where renderOid = renderObjOid . Tagged renderObjOid = renderOid . unTagged
+ Git: class (Eq o, Ord o, Show o) => IsOid o where renderOid = renderObjOid . Tagged renderObjOid = renderOid . untag
- Git: class (Applicative m, Monad m, Failure GitException m, IsOid (Oid m)) => Repository m where type family Oid m :: * type family TreeKind m :: * type family Tree m :: * -> * data family Options m parseObjOid sha = Tagged <$> parseOid sha createRef_ = (void .) . createRef updateRef_ = (void .) . updateRef allRefs = catMaybes <$> (mapM lookupRef =<< allRefNames) allRefNames = map refName <$> allRefs resolveRef name = lookupRef name >>= referenceToRef (Just name) traverseObjects_ = (void .) . traverseObjects traverseCommits_ = (void .) . traverseCommits traverseEntries_ = (void .) . traverseEntries buildPackFile _ _ = failure (BackendError "Backend does not support building pack files") buildPackIndex _ _ = failure (BackendError "Backend does not support building pack indexes") writePackFile _ = failure (BackendError "Backend does not support writing pack files")
+ Git: class (Applicative m, Monad m, Failure GitException m, IsOid (Oid m)) => Repository m where type family Oid m :: * data family Tree m :: * data family Options m :: * parseObjOid sha = Tagged <$> parseOid sha createReference_ = (void .) . createReference updateReference_ = (void .) . updateReference allReferences = catMaybes <$> (mapM lookupReference =<< allReferenceNames) allReferenceNames = map referenceName <$> allReferences resolveReference name = lookupReference name >>= referenceToRef (Just name) traverseObjects_ = (void .) . traverseObjects traverseCommits_ = (void .) . traverseCommits traverseEntries_ = (void .) . traverseEntries buildPackFile _ _ = failure (BackendError "Backend does not support building pack files") buildPackIndex _ _ = failure (BackendError "Backend does not support building pack indexes") writePackFile _ = failure (BackendError "Backend does not support writing pack files")
- Git: copyOid :: (Repository m, MonadGit m, Repository n, MonadGit n) => Oid m -> n (Oid n)
+ Git: copyOid :: (Repository m, Repository n) => Oid m -> n (Oid n)
- Git: createTree :: Repository m => RepositoryTreeT m a -> m (RepositoryTree m)
+ Git: createTree :: Repository m => TreeT m a -> m (TreeRef m)
- Git: data TreeT t m a
+ Git: data TreeT m a
- Git: dropEntry :: Repository m => FilePath -> RepositoryTreeT m ()
+ Git: dropEntry :: Repository m => FilePath -> TreeT m ()
- Git: getEntry :: Repository m => FilePath -> RepositoryTreeT m (Maybe (TreeEntry m))
+ Git: getEntry :: Repository m => FilePath -> TreeT m (Maybe (TreeEntry m))
- Git: getTreeEntry :: Repository m => RepositoryTree m -> FilePath -> m (Maybe (TreeEntry m))
+ Git: getTreeEntry :: Repository m => Tree m -> FilePath -> m (Maybe (TreeEntry m))
- Git: lookupTree :: Repository m => TreeOid m -> m (RepositoryTree m)
+ Git: lookupTree :: Repository m => TreeOid m -> m (Tree m)
- Git: mutateTree :: Repository m => RepositoryTree m -> RepositoryTreeT m a -> m (RepositoryTree m)
+ Git: mutateTree :: Repository m => Tree m -> TreeT m a -> m (TreeRef m)
- Git: putBlob :: Repository m => FilePath -> BlobOid m -> RepositoryTreeT m ()
+ Git: putBlob :: Repository m => FilePath -> BlobOid m -> TreeT m ()
- Git: putBlob' :: Repository m => FilePath -> BlobOid m -> BlobKind -> RepositoryTreeT m ()
+ Git: putBlob' :: Repository m => FilePath -> BlobOid m -> BlobKind -> TreeT m ()
- Git: putCommit :: Repository m => FilePath -> CommitOid m -> RepositoryTreeT m ()
+ Git: putCommit :: Repository m => FilePath -> CommitOid m -> TreeT m ()
- Git: putEntry :: Repository m => FilePath -> TreeEntry m -> RepositoryTreeT m ()
+ Git: putEntry :: Repository m => FilePath -> TreeEntry m -> TreeT m ()
- Git: putTree :: Repository m => FilePath -> TreeRef m -> RepositoryTreeT m ()
+ Git: putTree :: Repository m => FilePath -> TreeOid m -> TreeT m ()
- Git: resolveTreeRef :: Repository m => TreeRef m -> m (RepositoryTree m)
+ Git: resolveTreeRef :: Repository m => TreeRef m -> m (Tree m)
- Git: traverseEntries :: Repository m => (FilePath -> TreeEntry m -> m a) -> RepositoryTree m -> m [a]
+ Git: traverseEntries :: Repository m => (FilePath -> TreeEntry m -> m a) -> Tree m -> m [a]
- Git: traverseEntries_ :: Repository m => (FilePath -> TreeEntry m -> m a) -> RepositoryTree m -> m ()
+ Git: traverseEntries_ :: Repository m => (FilePath -> TreeEntry m -> m a) -> Tree m -> m ()
- Git: treeEntry :: Repository m => RepositoryTree m -> TreeEntry m
+ Git: treeEntry :: Repository m => Tree m -> TreeEntry m
- Git: treeEntryOid :: Repository m => TreeEntry m -> m (Oid m)
+ Git: treeEntryOid :: TreeEntry m -> !(TreeOid m)
- Git: treeRef :: RepositoryTree m -> TreeRef m
+ Git: treeRef :: Tree m -> TreeRef m
- Git: treeRefOid :: Repository m => TreeRef m -> m (TreeOid m)
+ Git: treeRefOid :: Repository m => TreeRef m -> TreeOid m
- Git: type TreeOid m = Tagged (RepositoryTree m) (Oid m)
+ Git: type TreeOid m = Tagged (Tree m) (Oid m)
- Git: type TreeRef m = ObjRef m (RepositoryTree m)
+ Git: type TreeRef m = ObjRef m (Tree m)
- Git: withNewTree :: Repository m => RepositoryTreeT m a -> m (a, RepositoryTree m)
+ Git: withNewTree :: Repository m => TreeT m a -> m (a, TreeRef m)
- Git: withTree :: Repository m => RepositoryTree m -> RepositoryTreeT m a -> m (a, RepositoryTree m)
+ Git: withTree :: Repository m => Tree m -> TreeT m a -> m (a, TreeRef m)

Files

Git.hs view
@@ -7,6 +7,7 @@ {-# LANGUAGE RankNTypes #-} {-# LANGUAGE RecordWildCards #-} {-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE ViewPatterns #-}  -- | Interface for working with Git repositories. module Git@@ -24,6 +25,9 @@        , Object(..)        , ObjRef(..)        , objectOid+       , SHA(..)+       , textToSha+       , shaToText         , Blob(..)        , BlobOid@@ -34,29 +38,29 @@        , blobEntry        , blobRefOid        , resolveBlobRef+       , createBlobUtf8+       , catBlob+       , catBlobUtf8+       , copyBlob+       , blobContentsToByteString+       , blobToByteString         , TreeT-       , RepositoryTree-       , RepositoryTreeT-       , MutableTree-       , MutableTreeT-       , PersistentTree-       , PersistentTreeT+       , TreeBuilder(..)+       , ModifiedBuilder(..)        , TreeEntry(..)        , TreeOid        , TreeRef        , createTree        , withNewTree        , mutateTree+       , mutateTreeRef+       , currentTree+       , currentTreeRef        , withTree-       , unsafeMutateTree-       , unsafeMutateTree_-       , unsafeWithTree-       , unsafeGetTree-       , unsafePutTree+       , withTreeRef        , dropEntry        , getEntry-       , getTreeEntry        , putBlob        , putBlob'        , putCommit@@ -64,12 +68,16 @@        , putTree        , resolveTreeRef        , treeEntry-       , treeEntryOid+       , getTreeEntryOid        , treeRef        , treeRefOid        , ModifyTreeResult(..)        , fromModifyTreeResult        , toModifyTreeResult+       , emptyTreeId+       , treeBlobEntries+       , copyTreeEntry+       , copyTree         , Commit(..)        , CommitOid@@ -81,12 +89,21 @@        , commitRef        , commitRefOid        , commitRefTarget+       , getCommitParents        , copyCommitName        , copyCommitOid        , nameOfCommit        , renderCommitName        , resolveCommitRef+       , commitTreeEntry+       , copyCommit+       , genericPushCommit +       , PinnedEntry(..)+       , commitHistoryFirstParent+       , commitEntryHistory+       , identifyEntry+        , Tag(..)        , TagOid        , TagRef@@ -95,6 +112,7 @@        , RefTarget(..)        , Reference(..)        , referenceToRef+       , resolveReferenceTree         , GitException(..)        , ModificationKind(..)@@ -102,6 +120,9 @@        , MergeResult(..)        , mergeStatus        , copyConflict+       , allMissingObjects+       , withNewRepository+       , withNewRepository'        ) where  import           Control.Applicative@@ -112,17 +133,32 @@ import           Control.Monad.IO.Class import           Control.Monad.Trans.Class import           Control.Monad.Trans.State+import qualified Data.Binary as Bin import           Data.ByteString (ByteString)+import qualified Data.ByteString as B+import qualified Data.ByteString.Base16 as B16 import           Data.Conduit+import qualified Data.Conduit.List as CList import           Data.Default+import           Data.Function+import           Data.HashMap.Strict (HashMap)+import qualified Data.HashMap.Strict as HashMap+import           Data.HashSet (HashSet)+import qualified Data.HashSet as HashSet+import           Data.Hashable+import           Data.List import           Data.Map (Map) import           Data.Maybe+import           Data.Monoid import           Data.Tagged import           Data.Text (Text) import qualified Data.Text as T+import qualified Data.Text.Encoding as T import           Data.Time+import           Data.Traversable hiding (mapM, forM, sequence) import           Data.Typeable-import           Filesystem.Path.CurrentOS+import           Filesystem (removeTree, isDirectory)+import           Filesystem.Path.CurrentOS hiding (null, concat) import           Prelude hiding (FilePath) import           System.Mem (performGC) @@ -138,17 +174,15 @@     renderOid :: o -> Text     renderOid = renderObjOid . Tagged     renderObjOid :: Tagged a o -> Text-    renderObjOid = renderOid . unTagged+    renderObjOid = renderOid . untag  -- | 'Repository' is the central point of contact between user code and -- Git data objects.  Every object must belong to some repository. class (Applicative m, Monad m, Failure GitException m, IsOid (Oid m))       => Repository m where-    type Oid m :: *-    type TreeKind m :: *-    type Tree m :: * -> *--    data Options m+    type Oid m     :: *+    data Tree m    :: *+    data Options m :: *      facts :: m RepositoryFacts @@ -157,27 +191,29 @@     parseObjOid sha = Tagged <$> parseOid sha      -- References-    createRef  :: Text -> RefTarget m (Commit m) -> m (Reference m (Commit m))-    createRef_ :: Text -> RefTarget m (Commit m) -> m ()-    createRef_ = (void .) . createRef-    lookupRef  :: Text -> m (Maybe (Reference m (Commit m)))-    updateRef  :: Text -> RefTarget m (Commit m) -> m (Reference m (Commit m))-    updateRef_ :: Text -> RefTarget m (Commit m) -> m ()-    updateRef_ = (void .) . updateRef-    deleteRef  :: Text -> m ()+    createReference  :: Text -> RefTarget m (Commit m)+                     -> m (Reference m (Commit m))+    createReference_ :: Text -> RefTarget m (Commit m) -> m ()+    createReference_ = (void .) . createReference+    lookupReference  :: Text -> m (Maybe (Reference m (Commit m)))+    updateReference  :: Text -> RefTarget m (Commit m)+                     -> m (Reference m (Commit m))+    updateReference_ :: Text -> RefTarget m (Commit m) -> m ()+    updateReference_ = (void .) . updateReference+    deleteReference  :: Text -> m () -    allRefs :: m [Reference m (Commit m)]-    allRefs = catMaybes <$> (mapM lookupRef =<< allRefNames)+    allReferences :: m [Reference m (Commit m)]+    allReferences = catMaybes <$> (mapM lookupReference =<< allReferenceNames) -    allRefNames :: m [Text]-    allRefNames = map refName <$> allRefs+    allReferenceNames :: m [Text]+    allReferenceNames = map referenceName <$> allReferences -    resolveRef :: Text -> m (Maybe (CommitRef m))-    resolveRef name = lookupRef name >>= referenceToRef (Just name)+    resolveReference :: Text -> m (Maybe (CommitRef m))+    resolveReference name = lookupReference name >>= referenceToRef (Just name)      -- Lookup     lookupCommit :: CommitOid m -> m (Commit m)-    lookupTree   :: TreeOid m -> m (RepositoryTree m)+    lookupTree   :: TreeOid m -> m (Tree m)     lookupBlob   :: BlobOid m -> m (Blob m)     lookupTag    :: TagOid m -> m (Tag m) @@ -204,19 +240,13 @@                    -> m [Object m]         -- ^ All the objects in between      -- Object creation-    newTree :: m (RepositoryTree m)-    cloneTree :: RepositoryTree m -> m (RepositoryTree m)-    traverseEntries :: (FilePath -> TreeEntry m -> m a) -> RepositoryTree m -> m [a]-    traverseEntries_ :: (FilePath -> TreeEntry m -> m a) -> RepositoryTree m -> m ()-    traverseEntries_ = (void .) . traverseEntries-    writeTree :: RepositoryTree m -> m (TreeOid m)+    newTreeBuilder :: Maybe (Tree m) -> m (TreeBuilder m) -    unsafeUpdateTree-        :: RepositoryTree m-        -> FilePath    -- path within the tree-        -> Bool        -- create subtree's leading up to path?-        -> (Maybe (TreeEntry m) -> ModifyTreeResult m)-        -> m (RepositoryTree m, Maybe (TreeEntry m))+    treeOid :: Tree m -> TreeOid m+    getTreeEntry :: Tree m -> FilePath -> m (Maybe (TreeEntry m))+    traverseEntries :: (FilePath -> TreeEntry m -> m a) -> Tree m -> m [a]+    traverseEntries_ :: (FilePath -> TreeEntry m -> m a) -> Tree m -> m ()+    traverseEntries_ = (void .) . traverseEntries      hashContents :: BlobContents m -> m (BlobOid m)     createBlob   :: BlobContents m -> m (BlobOid m)@@ -289,7 +319,7 @@  {- $oids -} type BlobOid m   = Tagged (Blob m) (Oid m)-type TreeOid m   = Tagged (RepositoryTree m) (Oid m)+type TreeOid m   = Tagged (Tree m) (Oid m) type CommitOid m = Tagged (Commit m) (Oid m) type TagOid m    = Tagged (Tag m) (Oid m) @@ -297,8 +327,8 @@ data RefTarget m a = RefObj !(ObjRef m a) | RefSymbolic !Text  data Reference m a = Reference-    { refName   :: !Text-    , refTarget :: !(RefTarget m a) }+    { referenceName   :: !Text+    , referenceTarget :: !(RefTarget m a) }  data CommitName m = CommitObjectId !(CommitOid m)                   | CommitRefName !Text@@ -307,23 +337,22 @@ instance Repository m => Show (CommitName m) where     show (CommitObjectId coid) = T.unpack (renderObjOid coid)     show (CommitRefName name)  = show name-    show (CommitReference ref) = show (refName ref)+    show (CommitReference ref) = show (referenceName ref)  nameOfCommit :: Commit m -> CommitName m nameOfCommit = CommitObjectId . commitOid  commitNameToRef :: Repository m => CommitName m -> m (Maybe (CommitRef m)) commitNameToRef (CommitObjectId coid) = return (Just (ByOid coid))-commitNameToRef (CommitRefName name)  = resolveRef name+commitNameToRef (CommitRefName name)  = resolveReference name commitNameToRef (CommitReference ref) = referenceToRef Nothing (Just ref)  renderCommitName :: Repository m => CommitName m -> Text renderCommitName (CommitObjectId coid) = renderObjOid coid renderCommitName (CommitRefName name)  = name-renderCommitName (CommitReference ref) = refName ref+renderCommitName (CommitReference ref) = referenceName ref -copyOid :: (Repository m, MonadGit m, Repository n, MonadGit n)-        => Oid m -> n (Oid n)+copyOid :: (Repository m, Repository n) => Oid m -> n (Oid n) copyOid = parseOid . renderOid  copyCommitOid :: (Repository m, MonadGit m, Repository n, MonadGit n)@@ -338,13 +367,13 @@     Just . CommitObjectId . Tagged <$> parseOid (renderObjOid coid) copyCommitName (CommitRefName name) = return (Just (CommitRefName name)) copyCommitName (CommitReference ref) =-    fmap CommitReference <$> lookupRef (refName ref)+    fmap CommitReference <$> lookupReference (referenceName ref)  {- $objects -} data ObjRef m a = ByOid !(Tagged a (Oid m)) | Known !a  type BlobRef m   = ObjRef m (Blob m)-type TreeRef m   = ObjRef m (RepositoryTree m)+type TreeRef m   = ObjRef m (Tree m) type CommitRef m = ObjRef m (Commit m) type TagRef m    = ObjRef m (Tag m) @@ -354,10 +383,10 @@               | TagObj       !(TagRef m)  objectOid :: Repository m => Object m -> m (Oid m)-objectOid (BlobObj ref)   = return . unTagged $ blobRefOid ref-objectOid (TreeObj ref)   = unTagged <$> treeRefOid ref-objectOid (CommitObj ref) = return . unTagged $ commitRefOid ref-objectOid (TagObj ref)    = return . unTagged $ tagRefOid ref+objectOid (BlobObj ref)   = return . untag $ blobRefOid ref+objectOid (TreeObj ref)   = return . untag $ treeRefOid ref+objectOid (CommitObj ref) = return . untag $ commitRefOid ref+objectOid (TagObj ref)    = return . untag $ tagRefOid ref  {- $blobs -} data Blob m = Blob { blobOid      :: !(BlobOid m)@@ -385,133 +414,128 @@   _ == _ = False  {- $trees -}-newtype TreeT t m a = TreeT { runTreeT :: StateT t m a }--data MutableTree-type MutableTreeT m a = TreeT (Tree m MutableTree) m a--data PersistentTree-type PersistentTreeT m a = TreeT (Tree m PersistentTree) m a--type RepositoryTree m = Tree m (TreeKind m)-type RepositoryTreeT m a = TreeT (RepositoryTree m) m a+newtype TreeT m a = TreeT { runTreeT :: StateT (TreeBuilder m) m a } -instance Functor m => Functor (TreeT t m) where+instance Functor m => Functor (TreeT m) where     fmap f (TreeT t) = TreeT (fmap f t) -instance Monad m => Monad (TreeT t m) where+instance Monad m => Monad (TreeT m) where     return x = TreeT (return x)     TreeT x >>= f = TreeT (x >>= runTreeT . f) -instance (Functor m, Monad m) => Applicative (TreeT t m) where+instance (Functor m, Monad m) => Applicative (TreeT m) where     pure = return     (<*>) = ap -instance (Functor m, MonadPlus m) => Alternative (TreeT t m) where+instance (Functor m, MonadPlus m) => Alternative (TreeT m) where     empty = mzero     (<|>) = mplus -instance (MonadPlus m) => MonadPlus (TreeT t m) where+instance (MonadPlus m) => MonadPlus (TreeT m) where     mzero       = TreeT $ mzero     m `mplus` n = TreeT $ runTreeT m `mplus` runTreeT n -instance (MonadFix m) => MonadFix (TreeT t m) where+instance (MonadFix m) => MonadFix (TreeT m) where     mfix f = TreeT $ mfix $ \ ~a -> runTreeT (f a) -instance MonadTrans (TreeT t) where+instance MonadTrans TreeT where     lift m = TreeT $ lift m -instance (MonadIO m) => MonadIO (TreeT t m) where+instance (MonadIO m) => MonadIO (TreeT m) where     liftIO = lift . liftIO -unsafeGetTree :: Monad m => RepositoryTreeT m (RepositoryTree m)-unsafeGetTree = TreeT get+getBuilder :: Monad m => TreeT m (TreeBuilder m)+getBuilder = TreeT get -unsafePutTree :: Monad m => RepositoryTree m -> RepositoryTreeT m ()-unsafePutTree = TreeT . put+putBuilder :: Monad m => TreeBuilder m -> TreeT m ()+putBuilder = TreeT . put -getEntry :: Repository m => FilePath -> RepositoryTreeT m (Maybe (TreeEntry m))+data BuilderAction = GetEntry | PutEntry | DropEntry+                   deriving (Eq, Show)++getEntry :: Repository m => FilePath -> TreeT m (Maybe (TreeEntry m)) getEntry path = do-    tr <- unsafeGetTree-    snd <$> lift (unsafeUpdateTree tr path False+    tb <- getBuilder+    snd <$> lift (queryTreeBuilder tb path GetEntry                   (toModifyTreeResult TreeEntryPersistent)) -getTreeEntry :: Repository m => RepositoryTree m -> FilePath -> m (Maybe (TreeEntry m))-getTreeEntry tree path =-    fst <$> (flip runStateT tree $ runTreeT (getEntry path))--putEntry :: Repository m => FilePath -> TreeEntry m -> RepositoryTreeT m ()+putEntry :: Repository m => FilePath -> TreeEntry m -> TreeT m () putEntry path ent = do-    tr <- unsafeGetTree-    tr' <- fst <$> lift (unsafeUpdateTree tr path True+    tb  <- getBuilder+    tb' <- fst <$> lift (queryTreeBuilder tb path PutEntry                          (const (TreeEntryMutated ent)))-    unsafePutTree tr'+    putBuilder tb' -dropEntry :: Repository m => FilePath -> RepositoryTreeT m ()+dropEntry :: Repository m => FilePath -> TreeT m () dropEntry path = do-    tr <- unsafeGetTree-    tr' <- fst <$> lift (unsafeUpdateTree tr path False+    tb  <- getBuilder+    tb' <- fst <$> lift (queryTreeBuilder tb path DropEntry                          (const TreeEntryDeleted))-    unsafePutTree tr'+    putBuilder tb' -putBlob' :: Repository m => FilePath -> BlobOid m -> BlobKind -> RepositoryTreeT m ()+putBlob' :: Repository m => FilePath -> BlobOid m -> BlobKind -> TreeT m () putBlob' path b kind = putEntry path (BlobEntry b kind) -putBlob :: Repository m => FilePath -> BlobOid m -> RepositoryTreeT m ()+putBlob :: Repository m => FilePath -> BlobOid m -> TreeT m () putBlob path b = putBlob' path b PlainBlob -putTree :: Repository m => FilePath -> TreeRef m -> RepositoryTreeT m ()-putTree path ent = putEntry path (TreeEntry ent)+putTree :: Repository m => FilePath -> TreeOid m -> TreeT m ()+putTree path t = putEntry path (TreeEntry t) -putCommit :: Repository m => FilePath -> CommitOid m -> RepositoryTreeT m ()+putCommit :: Repository m => FilePath -> CommitOid m -> TreeT m () putCommit path c = putEntry path (CommitEntry c) -withNewTree :: Repository m => RepositoryTreeT m a -> m (a, RepositoryTree m)-withNewTree (TreeT action) = runStateT action =<< newTree+doWithTree :: Repository m => Maybe (Tree m) -> TreeT m a -> m (a, TreeRef m)+doWithTree mtr act =+    fst <$> (runStateT (runTreeT go) =<< newTreeBuilder mtr)+  where+    go = liftM2 (,) act currentTreeRef -createTree :: Repository m => RepositoryTreeT m a -> m (RepositoryTree m)-createTree (TreeT action) = execStateT action =<< newTree+withTree :: Repository m => Tree m -> TreeT m a -> m (a, TreeRef m)+withTree tr = doWithTree (Just tr) -withTree :: Repository m-         => RepositoryTree m-         -> RepositoryTreeT m a-         -> m (a, RepositoryTree m)-withTree tr (TreeT action) = runStateT action =<< cloneTree tr+withTreeRef :: Repository m => TreeRef m -> TreeT m a -> m (a, TreeRef m)+withTreeRef ref action = do+    tree <- resolveTreeRef ref+    doWithTree (Just tree) action -unsafeWithTree :: Repository m-               => Tree m MutableTree -> MutableTreeT m a-               -> m (a, Tree m MutableTree)-unsafeWithTree tr (TreeT action) = runStateT action tr+mutateTree :: Repository m => Tree m -> TreeT m a -> m (TreeRef m)+mutateTree tr action = snd <$> withTree tr action -mutateTree :: Repository m-           => RepositoryTree m -> RepositoryTreeT m a-           -> m (RepositoryTree m)-mutateTree tr (TreeT action) = execStateT action =<< cloneTree tr+mutateTreeRef :: Repository m => TreeRef m -> TreeT m a -> m (TreeRef m)+mutateTreeRef tr action = snd <$> withTreeRef tr action -unsafeMutateTree :: Repository m-                 => Tree m MutableTree -> MutableTreeT m a-                 -> m (Tree m MutableTree)-unsafeMutateTree tr (TreeT action) = execStateT action tr+currentTreeRef :: Repository m => TreeT m (TreeRef m)+currentTreeRef = do+    tb <- getBuilder+    (tb', tref) <- lift $ writeTreeBuilder tb+    putBuilder tb'+    return tref -unsafeMutateTree_ :: Repository m-                  => Tree m MutableTree -> MutableTreeT m a -> m ()-unsafeMutateTree_ = (void .) . unsafeMutateTree+currentTree :: Repository m => TreeT m (Tree m)+currentTree = lift . resolveTreeRef =<< currentTreeRef +withNewTree :: Repository m => TreeT m a -> m (a, TreeRef m)+withNewTree = doWithTree Nothing++createTree :: Repository m => TreeT m a -> m (TreeRef m)+createTree action = snd <$> withNewTree action+ data TreeEntry m = BlobEntry   { blobEntryOid   :: !(BlobOid m)                                , blobEntryKind  :: !BlobKind }-                 | TreeEntry   { treeEntryRef   :: !(TreeRef m) }-                 | CommitEntry { commitEntryRef :: !(CommitOid m) }+                 | TreeEntry   { treeEntryOid   :: !(TreeOid m) }+                 | CommitEntry { commitEntryOid :: !(CommitOid m) } -treeEntryOid :: Repository m => TreeEntry m -> m (Oid m)-treeEntryOid (BlobEntry boid _) = return $ unTagged boid-treeEntryOid (TreeEntry tref)   = unTagged <$> treeRefOid tref-treeEntryOid (CommitEntry coid) = return $ unTagged coid+getTreeEntryOid :: Repository m => TreeEntry m -> Oid m+getTreeEntryOid (BlobEntry boid _) = untag boid+getTreeEntryOid (TreeEntry toid)   = untag toid+getTreeEntryOid (CommitEntry coid) = untag coid  blobEntry :: Repository m => BlobOid m -> BlobKind -> TreeEntry m blobEntry = BlobEntry -treeEntry :: Repository m => RepositoryTree m -> TreeEntry m-treeEntry = TreeEntry . treeRef+treeEntry :: Repository m => Tree m -> TreeEntry m+treeEntry = TreeEntry . treeOid  commitEntry :: Repository m => Commit m -> TreeEntry m commitEntry = CommitEntry . commitOid@@ -534,14 +558,14 @@ toModifyTreeResult f (Just x) = f x  -- | A 'Tree' is anything that is "treeish".-treeRef :: RepositoryTree m -> TreeRef m+treeRef :: Tree m -> TreeRef m treeRef = Known -treeRefOid :: Repository m => TreeRef m -> m (TreeOid m)-treeRefOid (ByOid x) = return x-treeRefOid (Known x) = writeTree x+treeRefOid :: Repository m => TreeRef m -> TreeOid m+treeRefOid (ByOid x) = x+treeRefOid (Known x) = treeOid x -resolveTreeRef :: Repository m => TreeRef m -> m (RepositoryTree m)+resolveTreeRef :: Repository m => TreeRef m -> m (Tree m) resolveTreeRef (ByOid oid) = lookupTree oid resolveTreeRef (Known obj) = return obj @@ -595,12 +619,12 @@ referenceToRef mname mref =     case mref of         Nothing -> return Nothing-        Just (Reference { refTarget = RefObj x }) ->+        Just (Reference { referenceTarget = RefObj x }) ->             return (Just x)-        Just ref@(Reference { refTarget = RefSymbolic name' }) ->+        Just ref@(Reference { referenceTarget = RefSymbolic name' }) ->             if fromMaybe name' mname /= name'-            then resolveRef name'-            else failure (ReferenceLookupFailed (refName ref))+            then resolveReference name'+            else failure (ReferenceLookupFailed (referenceName ref))  {- $tags -} @@ -694,6 +718,490 @@                     <*> pure cs  {- $miscellaneous -}++newtype SHA = SHA B.ByteString deriving (Eq, Ord, Read)++instance Show SHA where+    show = T.unpack . shaToText++instance Bin.Binary SHA where+    put (SHA t) = Bin.put t+    get = SHA <$> Bin.get++instance Hashable SHA where+    hashWithSalt salt (SHA bs) = hashWithSalt salt bs++instance IsOid SHA where+    renderOid = shaToText++shaToText :: SHA -> Text+shaToText (SHA bs) = T.decodeUtf8 (B16.encode bs)++textToSha :: Monad m => Text -> m SHA+textToSha t =+    case B16.decode $ T.encodeUtf8 t of+        (bs, "") -> return (SHA bs)+        _ -> fail "Invalid base16 encoding"++createBlobUtf8 :: Repository m => Text -> m (BlobOid m)+createBlobUtf8 = createBlob . BlobString . T.encodeUtf8++catBlob :: Repository m => Text -> m ByteString+catBlob str =+    if len == 40+    then do+        oid <- parseOid str+        lookupBlob (Tagged oid) >>= blobToByteString++    else do+        obj <- lookupObject str+        case obj of+            BlobObj (ByOid oid) -> lookupBlob oid >>= blobToByteString+            BlobObj (Known x)   -> blobToByteString x+            _ -> failure (ObjectLookupFailed str len)+  where+    len = T.length str++catBlobUtf8 :: Repository m => Text -> m Text+catBlobUtf8 = catBlob >=> return . T.decodeUtf8++blobContentsToByteString :: Repository m => BlobContents m -> m ByteString+blobContentsToByteString (BlobString bs) = return bs+blobContentsToByteString (BlobStream bs) = do+    strs <- bs $$ CList.consume+    return (B.concat strs)+blobContentsToByteString (BlobSizedStream bs _) = do+    strs <- bs $$ CList.consume+    return (B.concat strs)++blobToByteString :: Repository m => Blob m -> m ByteString+blobToByteString (Blob _ contents) = blobContentsToByteString contents++splitPath :: FilePath -> [Text]+splitPath path = T.splitOn "/" text+  where text = case toText path of+                 Left x  -> error $ "Invalid path: " ++ T.unpack x+                 Right y -> y++data ModifiedBuilder m = ModifiedBuilder (TreeBuilder m)+                       | BuilderUnchanged (TreeBuilder m)++instance Monoid (ModifiedBuilder m) where+    mempty = BuilderUnchanged (error "ModifiedBuilder is a semigroup")+    BuilderUnchanged _ `mappend` BuilderUnchanged b2 = BuilderUnchanged b2+    ModifiedBuilder b1  `mappend` BuilderUnchanged _ = ModifiedBuilder b1+    BuilderUnchanged _ `mappend` ModifiedBuilder b2  = ModifiedBuilder b2+    ModifiedBuilder _  `mappend` ModifiedBuilder b2  = ModifiedBuilder b2++fromBuilderMod :: ModifiedBuilder m -> TreeBuilder m+fromBuilderMod (BuilderUnchanged tb) = tb+fromBuilderMod (ModifiedBuilder tb)  = tb++data TreeBuilder m = TreeBuilder+    { mtbBaseTreeRef    :: Maybe (TreeRef m)+    , mtbPendingUpdates :: HashMap Text (TreeBuilder m)+    , mtbNewBuilder     :: Maybe (Tree m) -> m (TreeBuilder m)+    , mtbWriteContents  :: TreeBuilder m -> m (ModifiedBuilder m, TreeRef m)+    , mtbLookupEntry    :: Text -> m (Maybe (TreeEntry m))+    , mtbEntryCount     :: m Int+    , mtbPutEntry       :: TreeBuilder m -> Text -> TreeEntry m+                        -> m (ModifiedBuilder m)+    , mtbDropEntry      :: TreeBuilder m -> Text -> m (ModifiedBuilder m)+    }++instance Monad m => Monoid (TreeBuilder m) where+    mempty = TreeBuilder+        { mtbBaseTreeRef    = Nothing+        , mtbPendingUpdates = HashMap.empty+        , mtbNewBuilder     = error "Implement TreeBuilder.mtbNewBuilder"+        , mtbWriteContents  = error "Implement TreeBuilder.mtbWriteContents"+        , mtbLookupEntry    = \_ -> return Nothing+        , mtbEntryCount     = return 0+        , mtbPutEntry       = \tb _ _ -> return (BuilderUnchanged tb)+        , mtbDropEntry      = \tb _ -> return (BuilderUnchanged tb)+        }+    tb1 `mappend` tb2 = tb2+        { mtbBaseTreeRef    = mtbBaseTreeRef tb1+        , mtbPendingUpdates = mtbPendingUpdates tb1+        }++emptyTreeId :: Text+emptyTreeId = "4b825dc642cb6eb9a060e54bf8d69288fbee4904"++-- | Perform a query action on a TreeBuilder using the supplied action kind+--   and user function.+--+--   This is a complex algorithm which has been rewritten many times, so I+--   will try to guide you through it as best I can.+queryTreeBuilder :: Repository m+                  => TreeBuilder m+                  -> FilePath+                  -> BuilderAction+                  -> (Maybe (TreeEntry m) -> ModifyTreeResult m)+                  -> m (TreeBuilder m, Maybe (TreeEntry m))+queryTreeBuilder builder path kind f = do+    (mtb, mtresult) <- walk (BuilderUnchanged builder) (splitPath path)+    return (fromBuilderMod mtb, fromModifyTreeResult mtresult)+  where+    walk _ [] = error "queryTreeBuilder called without a path"+    walk bm (name:names) = do+        let tb = fromBuilderMod bm+        y <- case HashMap.lookup name (mtbPendingUpdates tb) of+            Just x  -> return $ Left (BuilderUnchanged x)+            Nothing -> do+                mentry <- mtbLookupEntry tb name+                case mentry of+                    Nothing+                        | kind == PutEntry && not (null names) ->+                            Left . ModifiedBuilder+                                <$> mtbNewBuilder tb Nothing+                        | otherwise -> return $ Right Nothing+                    Just x -> return $ Right (Just x)+        update bm name names y++    doUpdate GetEntry bm name sbm = do+        (_, tref) <- writeTreeBuilder (fromBuilderMod sbm)+        returnTree bm name $ f (Just (TreeEntry (treeRefOid tref)))+    doUpdate _ bm name _ = returnTree bm name (f Nothing)++    update bm name [] (Left sbm) = doUpdate kind bm name sbm+    update bm name [] (Right y)  = returnTree bm name (f y)++    update bm _ _ (Right Nothing) = return (bm, TreeEntryNotFound)+    update _ _ _ (Right (Just BlobEntry {})) =+        failure TreeCannotTraverseBlob+    update _ _ _ (Right (Just CommitEntry {})) =+        failure TreeCannotTraverseCommit++    update bm name names arg = do+        sbm <- case arg of+            Left sbm' -> return sbm'+            Right (Just (TreeEntry st')) -> do+                tree <- lookupTree st'+                ModifiedBuilder+                    <$> mtbNewBuilder (fromBuilderMod bm) (Just tree)+            _ -> error "queryTreeBuilder encountered the impossible"++        (sbm', z) <- walk sbm names+        let bm' = bm <> postUpdate bm sbm' name+        return $ bm' `seq` (bm', z)++    returnTree bm@(fromBuilderMod -> tb) n z = do+        bm' <- case z of+            TreeEntryNotFound     -> return bm+            TreeEntryPersistent _ -> return bm+            TreeEntryDeleted      -> do+                bm' <- mtbDropEntry tb tb n+                let tb'   = fromBuilderMod bm'+                    upds' = mtbPendingUpdates tb'+                return $+                    if HashMap.member n upds'+                     then ModifiedBuilder tb'+                         { mtbPendingUpdates = HashMap.delete n upds' }+                     else bm'+            TreeEntryMutated z'   -> mtbPutEntry tb tb n z'+        let bm'' = bm <> bm'+        return $ bm'' `seq` (bm'', z)++    postUpdate bm (BuilderUnchanged _) _ = bm+    postUpdate (fromBuilderMod -> tb) (ModifiedBuilder sbm) name =+        ModifiedBuilder $ tb+            { mtbPendingUpdates =+                   HashMap.insert name sbm (mtbPendingUpdates tb) }++-- | Write out a tree to its repository.  If it has already been written,+--   nothing will happen.+writeTreeBuilder :: Repository m+                 => TreeBuilder m+                 -> m (TreeBuilder m, TreeRef m)+writeTreeBuilder builder = do+    (bm, mtref) <- go (BuilderUnchanged builder)+    tref <- case mtref of+        Nothing -> do+            emptyTreeOid <- parseObjOid emptyTreeId+            return $ ByOid emptyTreeOid+        Just tref -> return tref+    return (fromBuilderMod bm, tref)+  where+    go bm = do+        let upds = mtbPendingUpdates (fromBuilderMod bm)+        bm' <- if HashMap.size upds == 0+               then return bm+               else do+                   bm' <- foldM update bm $ HashMap.toList upds+                   return $ ModifiedBuilder (fromBuilderMod bm')+                       { mtbPendingUpdates = HashMap.empty }+        let tb' = fromBuilderMod bm'+        cnt <- mtbEntryCount tb'+        if cnt == 0+            then return (bm', Nothing)+            else do+                 (bm'', tref) <- mtbWriteContents tb' tb'+                 return (bm' <> bm'', Just tref)++    update bm (k,v) = do+        let tb = fromBuilderMod bm+        -- The intermediate TreeBuilder will be dropped after this fold is+        -- completed, by setting mtbPendingUpdates to HashMap.empty, above.+        (_,mtref) <- go (BuilderUnchanged v)+        bm' <- case mtref of+            Nothing   -> mtbDropEntry tb tb k+            Just tref -> mtbPutEntry tb tb k (TreeEntry (treeRefOid tref))+        return $ bm <> bm'++treeBlobEntries :: Repository m => Tree m -> m [(FilePath,TreeEntry m)]+treeBlobEntries tree =+    mconcat <$> traverseEntries go tree+  where+    go fp e@(BlobEntry _ PlainBlob)      = return [(fp,e)]+    go fp e@(BlobEntry _ ExecutableBlob) = return [(fp,e)]+    go _ _ = return []++commitTreeEntry :: Repository m+                => Commit m+                -> FilePath+                -> m (Maybe (TreeEntry m))+commitTreeEntry c path =+    flip getTreeEntry path =<< resolveTreeRef (commitTree c)++copyBlob :: (Repository m, Repository (t m), MonadTrans t)+         => BlobRef m+         -> HashSet Text+         -> t m (BlobOid (t m), HashSet Text)+copyBlob blobr needed = do+    let oid = untag (blobRefOid blobr)+        sha = renderOid oid+    oid2 <- parseOid (renderOid oid)+    if HashSet.member sha needed+        then do+        bs <- lift $ blobToByteString+              =<< resolveBlobRef (ByOid (Tagged oid))+        boid <- createBlob (BlobString bs)++        let x = HashSet.delete sha needed+        return $ boid `seq` x `seq` (boid, x)++        else return (Tagged oid2, needed)++copyTreeEntry :: (Repository m, Repository (t m), MonadTrans t)+              => TreeEntry m+              -> HashSet Text+              -> t m (TreeEntry (t m), HashSet Text)+copyTreeEntry (BlobEntry oid kind) needed = do+    (b,needed') <- copyBlob (ByOid oid) needed+    return (BlobEntry b kind, needed')+copyTreeEntry (CommitEntry oid) needed = do+    coid <- parseOid (renderObjOid oid)+    return (CommitEntry (Tagged coid), needed)+copyTreeEntry (TreeEntry _) _ = error "This should never be called"++copyTree :: (Repository m, Repository (t m), MonadTrans t)+         => TreeRef m+         -> HashSet Text+         -> t m (TreeRef (t m), HashSet Text)+copyTree tr needed = do+    let oid = untag (treeRefOid tr)+        sha = renderOid oid+    oid2 <- parseOid (renderOid oid)+    if HashSet.member sha needed+        then do+        tree            <- lift $ resolveTreeRef tr+        entries         <- lift $ traverseEntries (curry return) tree+        (needed', tref) <- withNewTree $ foldM doCopyTreeEntry needed entries++        let x = HashSet.delete sha needed'+        return $ tref `seq` x `seq` (tref, x)++        else return (ByOid (Tagged oid2), needed)+  where+    doCopyTreeEntry :: (Repository m, Repository (t m), MonadTrans t)+                    => HashSet Text -> (FilePath, TreeEntry m)+                    -> TreeT (t m) (HashSet Text)+    doCopyTreeEntry needed' (_,TreeEntry {}) = return needed'+    doCopyTreeEntry needed' (fp,ent) = do+        (ent2,needed'') <- lift $ copyTreeEntry ent needed'+        putEntry fp ent2+        return needed''++copyCommit :: (Repository m, Repository (t m), MonadTrans t)+           => CommitRef m+           -> Maybe Text+           -> HashSet Text+           -> t m (CommitRef (t m), HashSet Text)+copyCommit cr mref needed = do+    let oid = untag (commitRefOid cr)+        sha = renderOid oid+    commit <- lift $ resolveCommitRef cr+    oid2   <- parseOid sha+    if HashSet.member sha needed+        then do+        let parents = commitParents commit+        (parentRefs,needed') <- foldM copyParent ([],needed) parents+        (tr,needed'') <- copyTree (commitTree commit) needed'++        commit' <- createCommit (reverse parentRefs) tr+            (commitAuthor commit)+            (commitCommitter commit)+            (commitLog commit)+            mref++        let cref = commitRef $! commit'+            x    = HashSet.delete sha needed''+        return $ cref `seq` x `seq` (cref, x)++        else return (ByOid (Tagged oid2), needed)+  where+    copyParent (prefs,needed') cref = do+        (cref2,needed'') <- copyCommit cref Nothing needed'+        let x = cref2 `seq` (cref2:prefs)+        return $ x `seq` needed'' `seq` (x,needed'')++-- | Given a list of objects (commit and top-level trees) return by+--   'missingObjects', expand it to include all subtrees and blobs as well.+--   Ordering is preserved.+allMissingObjects :: Repository m => [Object m] -> m [Object m]+allMissingObjects objs =+    fmap concat . forM objs $ \obj -> case obj of+        TreeObj ref -> do+            tr       <- resolveTreeRef ref+            subobjss <- flip traverseEntries tr $ \_ ent ->+                return $ case ent of+                    BlobEntry oid _ -> [BlobObj (ByOid oid)]+                    TreeEntry oid   -> [TreeObj (ByOid oid)]+                    _ -> []+            return (obj:concat subobjss)+        _ -> return [obj]++-- | Fast-forward push a reference between repositories using a recursive+--   copy.  This can be extremely slow, but always works.+genericPushCommit :: (Repository m, Repository (t m), MonadTrans t)+                  => CommitName m -> Text -> t m (CommitRef (t m))+genericPushCommit cname remoteRefName = do+    mrref    <- lookupReference remoteRefName+    commits1 <- lift $ traverseCommits crefToSha cname+    fastForward <- case mrref of+        Just rref -> do+            mrsha <- referenceSha rref+            case mrsha of+                Nothing -> failure (PushNotFastForward $+                                    "Could not find SHA for " <> remoteRefName)+                Just rsha+                    | rsha `elem` commits1 -> do+                        roid <- lift $ parseOid rsha+                        return $ Just (Just (CommitObjectId (Tagged roid)))+                    | otherwise -> do+                        failure (PushNotFastForward $+                                 "SHA " <> rsha+                                        <> " not found in remote")+        Nothing -> return (Just Nothing)+    case fastForward of+        Nothing -> failure (PushNotFastForward "unexpected")+        Just liftedMrref -> do+            objs <- lift $ allMissingObjects+                        =<< missingObjects liftedMrref cname+            shas <- mapM (\obj -> renderOid <$> lift (objectOid obj)) objs+            mref <- lift $ commitNameToRef cname+            case mref of+                Nothing -> failure (ReferenceLookupFailed (T.pack (show cname)))+                Just ref -> do+                    (cref,_) <- copyCommit ref Nothing (HashSet.fromList shas)+                    -- jww (2013-04-18): This is something the user must+                    -- decide to do+                    -- updateRef_ remoteRefName (RefObj cref)+                    return cref+  where+    referenceSha ref = do+        r <- referenceToRef Nothing (Just ref)+        return $ renderObjOid . commitRefOid <$> r++    crefToSha cref  = return (renderObjOid (commitRefOid cref))++commitHistoryFirstParent :: Repository m => Commit m -> m [Commit m]+commitHistoryFirstParent c =+    case commitParents c of+        []    -> return [c]+        (p:_) -> do ps <- commitHistoryFirstParent =<< resolveCommitRef p+                    return (c:ps)++data PinnedEntry m = PinnedEntry+    { pinnedOid    :: Oid m+    , pinnedCommit :: Commit m+    , pinnedEntry  :: TreeEntry m+    }++identifyEntry :: Repository m => Commit m -> TreeEntry m -> m (PinnedEntry m)+identifyEntry co x = do+    let oid = case x of+            BlobEntry oid' _ -> untag oid'+            TreeEntry oid'   -> untag oid'+            CommitEntry oid' -> untag oid'+    return (PinnedEntry oid co x)++commitEntryHistory :: Repository m => Commit m -> FilePath -> m [PinnedEntry m]+commitEntryHistory c path =+    map head . filter (not . null) . groupBy ((==) `on` pinnedOid) <$> go c+  where+    go co = do+        entry <- getCommitTreeEntry co+        rest  <- case commitParents co of+            []    -> return []+            (p:_) -> go =<< resolveCommitRef p+        return $ maybe rest (:rest) entry++    getCommitTreeEntry co = do+        ce <- commitTreeEntry co path+        case ce of+            Nothing  -> return Nothing+            Just ce' -> Just <$> identifyEntry co ce'++getCommitParents :: Repository m => Commit m -> m [Commit m]+getCommitParents = traverse resolveCommitRef . commitParents++resolveReferenceTree :: Repository m => Text -> m (Maybe (Tree m))+resolveReferenceTree refName = do+    c <- resolveReference refName+    case c of+        Nothing -> return Nothing+        Just c' ->+            Just <$> (resolveCommitRef c' >>= resolveTreeRef . commitTree)++withNewRepository :: (Repository (t m), MonadGit (t m),+                      MonadBaseControl IO m, MonadIO m, MonadTrans t)+                  => RepositoryFactory t m c+                  -> FilePath -> t m a -> m a+withNewRepository factory path action = do+    liftIO $ do+        exists <- isDirectory path+        when exists $ removeTree path++    -- we want exceptions to leave the repo behind+    a <- withRepository' factory (defaultOptions factory)+        { repoPath       = path+        , repoIsBare     = True+        , repoAutoCreate = True+        } action++    liftIO $ do+        exists <- isDirectory path+        when exists $ removeTree path++    return a++withNewRepository' :: (Repository (t m), MonadGit (t m),+                       MonadBaseControl IO m, MonadIO m, MonadTrans t)+                   => RepositoryFactory t m c -> FilePath -> t m a -> m a+withNewRepository' factory path action =+    Exc.bracket_ recover recover $+        withRepository' factory (defaultOptions factory)+            { repoPath       = path+            , repoIsBare     = True+            , repoAutoCreate = True+            } action+  where+    recover = liftIO $ do+        exists <- isDirectory path+        when exists $ removeTree path+  data RepositoryOptions = RepositoryOptions     { repoPath       :: !FilePath
gitlib.cabal view
@@ -1,5 +1,5 @@ Name:                gitlib-Version:             1.2.1+Version:             1.3.1 Synopsis:            API library for working with Git repositories License-file:        LICENSE License:             MIT@@ -40,17 +40,22 @@     ghc-options: -Wall     build-depends:           base                 >= 3 && < 5+        , base16-bytestring    >= 0.1.1.5+        , binary               >= 0.5.1.0         , bytestring           >= 0.9.2.1         , conduit              >= 1.0.0         , containers           >= 0.4.2.1         , data-default         >= 0.5.0         , failure              >= 0.2.0.1+        , hashable             >= 1.1.2.5         , lifted-base          >= 0.2+        , system-fileio        >= 0.3.11         , system-filepath      >= 0.4.7         , tagged               >= 0.2.3.1-        , transformers         >= 0.3.0.0         , text                 >= 0.11.2         , time                 >= 1.4+        , transformers         >= 0.3.0.0+        , unordered-containers >= 0.2.3.0     exposed-modules:         Git         Git.Tutorial