gitlib 1.4.0 → 2.0.0.0
raw patch · 13 files changed
+1200/−1257 lines, 13 filesdep −directorydep −doctestdep −doctest-propdep ~basePVP ok
version bump matches the API change (PVP)
Dependencies removed: directory, doctest, doctest-prop, filepath
Dependency ranges changed: base
API changes (from Hackage documentation)
- Git: Added :: ModificationKind
- Git: BackendError :: Text -> GitException
- Git: Blob :: !(BlobOid m) -> !(BlobContents m) -> Blob m
- Git: BlobCreateFailed :: GitException
- Git: BlobEmptyCreateFailed :: GitException
- Git: BlobEncodingUnknown :: Text -> GitException
- Git: BlobEntry :: !(BlobOid m) -> !BlobKind -> TreeEntry m
- Git: BlobLookupFailed :: GitException
- Git: BlobObj :: !(Blob m) -> Object m
- Git: BlobObjOid :: !(BlobOid m) -> ObjectOid m
- Git: BlobSizedStream :: !(ByteSource m) -> !Int -> BlobContents m
- Git: BlobStream :: !(ByteSource m) -> BlobContents m
- Git: BlobString :: !ByteString -> BlobContents m
- Git: BothAdded :: MergeStatus
- Git: BothModified :: MergeStatus
- Git: BothTypeChanged :: MergeStatus
- Git: BuilderUnchanged :: (TreeBuilder m) -> ModifiedBuilder m
- Git: Commit :: !(CommitOid m) -> ![CommitOid m] -> !(TreeOid m) -> !Signature -> !Signature -> !Text -> !Text -> Commit m
- Git: CommitCreateFailed :: GitException
- Git: CommitEntry :: !(CommitOid m) -> TreeEntry m
- Git: CommitLookupFailed :: Text -> GitException
- Git: CommitObj :: !(Commit m) -> Object m
- Git: CommitObjOid :: !(CommitOid m) -> ObjectOid m
- Git: CommitObjectId :: !(CommitOid m) -> CommitName m
- Git: CommitReference :: !(Reference m) -> CommitName m
- Git: CommitReferenceName :: !Text -> CommitName m
- Git: Deleted :: ModificationKind
- Git: ExecutableBlob :: BlobKind
- Git: GitError :: Text -> GitException
- Git: LeftDeletedRightModified :: MergeStatus
- Git: LeftDeletedRightTypeChanged :: MergeStatus
- Git: LeftModifiedRightDeleted :: MergeStatus
- Git: LeftModifiedRightTypeChanged :: MergeStatus
- Git: LeftTypeChangedRightDeleted :: MergeStatus
- Git: LeftTypeChangedRightModified :: MergeStatus
- Git: MergeConflicted :: CommitOid m -> CommitOid m -> CommitOid m -> Map FilePath (ModificationKind, ModificationKind) -> MergeResult m
- Git: MergeSuccess :: CommitOid m -> MergeResult m
- Git: Modified :: ModificationKind
- Git: ModifiedBuilder :: (TreeBuilder m) -> ModifiedBuilder m
- Git: NoConflict :: MergeStatus
- Git: ObjectLookupFailed :: Text -> Int -> GitException
- Git: ObjectRefRequiresFullOid :: GitException
- Git: OidCopyFailed :: GitException
- Git: OidParseFailed :: Text -> GitException
- Git: PinnedEntry :: Oid m -> Commit m -> TreeEntry m -> PinnedEntry m
- Git: PlainBlob :: BlobKind
- Git: PushNotFastForward :: Text -> GitException
- Git: QuotaHardLimitExceeded :: Int -> Int -> GitException
- Git: RefCannotCreateFromPartialOid :: GitException
- Git: RefObj :: !(CommitOid m) -> RefTarget m
- Git: RefSymbolic :: !Text -> RefTarget m
- Git: Reference :: !Text -> !(RefTarget m) -> Reference m
- Git: ReferenceCreateFailed :: GitException
- Git: ReferenceDeleteFailed :: Text -> GitException
- Git: ReferenceListingFailed :: GitException
- Git: ReferenceLookupFailed :: Text -> GitException
- Git: RepositoryCannotAccess :: Text -> GitException
- Git: RepositoryFactory :: (RepositoryOptions -> m c) -> (forall a. c -> t m a -> m a) -> (c -> m ()) -> t m c -> !RepositoryOptions -> m () -> m () -> RepositoryFactory t m c
- Git: RepositoryFacts :: !Bool -> RepositoryFacts
- Git: RepositoryInvalid :: GitException
- Git: RepositoryNotExist :: GitException
- Git: RepositoryOptions :: !FilePath -> !Bool -> !Bool -> RepositoryOptions
- Git: SHA :: ByteString -> SHA
- Git: Signature :: !Text -> !Text -> !ZonedTime -> Signature
- Git: SymlinkBlob :: BlobKind
- Git: Tag :: !(TagOid m) -> !(CommitOid m) -> Tag m
- Git: TagObj :: !(Tag m) -> Object m
- Git: TagObjOid :: !(TagOid m) -> ObjectOid m
- Git: TranslationException :: Text -> GitException
- Git: TreeBuilder :: Maybe (TreeOid m) -> HashMap Text (TreeBuilder m) -> (Maybe (Tree m) -> m (TreeBuilder m)) -> (TreeBuilder m -> m (ModifiedBuilder m, TreeOid 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: TreeBuilderCreateFailed :: GitException
- Git: TreeBuilderInsertFailed :: Text -> GitException
- Git: TreeBuilderRemoveFailed :: Text -> GitException
- Git: TreeBuilderWriteFailed :: Text -> GitException
- Git: TreeCannotTraverseBlob :: GitException
- Git: TreeCannotTraverseCommit :: GitException
- Git: TreeCreateFailed :: Text -> GitException
- Git: TreeEntry :: !(TreeOid m) -> TreeEntry m
- Git: TreeEntryDeleted :: ModifyTreeResult m
- Git: TreeEntryLookupFailed :: FilePath -> GitException
- Git: TreeEntryMutated :: (TreeEntry m) -> ModifyTreeResult m
- Git: TreeEntryNotFound :: ModifyTreeResult m
- Git: TreeEntryPersistent :: (TreeEntry m) -> ModifyTreeResult m
- Git: TreeLookupFailed :: GitException
- Git: TreeObj :: !(Tree m) -> Object m
- Git: TreeObjOid :: !(TreeOid m) -> ObjectOid m
- Git: TreeUpdateFailed :: GitException
- Git: TreeWalkFailed :: GitException
- Git: TypeChanged :: ModificationKind
- Git: Unchanged :: ModificationKind
- Git: UnknownBlob :: BlobKind
- Git: allMissingObjects :: Repository m => [ObjectOid m] -> m [ObjectOid m]
- Git: allReferenceNames :: Repository m => m [Text]
- Git: allReferences :: Repository m => m [Reference m]
- Git: blobContents :: Blob m -> !(BlobContents m)
- Git: blobContentsToByteString :: Repository m => BlobContents m -> m ByteString
- Git: blobEntry :: Repository m => BlobOid m -> BlobKind -> TreeEntry m
- Git: blobEntryKind :: TreeEntry m -> !BlobKind
- Git: blobEntryOid :: TreeEntry m -> !(BlobOid m)
- Git: blobOid :: Blob m -> !(BlobOid m)
- Git: blobToByteString :: Repository m => Blob m -> m ByteString
- Git: buildPackFile :: Repository m => FilePath -> [Either (CommitOid m) (TreeOid m)] -> m FilePath
- Git: buildPackIndex :: Repository m => FilePath -> ByteString -> m (Text, FilePath, FilePath)
- Git: catBlob :: Repository m => Text -> m ByteString
- Git: catBlobUtf8 :: Repository m => Text -> m Text
- 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 :: * 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 >>= referenceToOid (Just name) lookupObjectOid = fmap objectToObjOid . lookupObject 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: closeRepository :: RepositoryFactory t m c -> c -> m ()
- Git: commitAuthor :: Commit m -> !Signature
- Git: commitCommitter :: Commit m -> !Signature
- Git: commitEncoding :: Commit m -> !Text
- Git: commitEntry :: Repository m => Commit m -> TreeEntry m
- 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: commitLog :: Commit m -> !Text
- Git: commitNameToOid :: Repository m => CommitName m -> m (Maybe (CommitOid m))
- Git: commitOid :: Commit m -> !(CommitOid m)
- Git: commitParents :: Commit m -> ![CommitOid m]
- Git: commitRefTarget :: Commit m -> RefTarget m
- Git: commitTree :: Commit m -> !(TreeOid m)
- Git: commitTreeEntry :: Repository m => Commit m -> FilePath -> m (Maybe (TreeEntry m))
- Git: copyBlob :: (Repository m, Repository (t m), MonadTrans t) => BlobOid m -> HashSet Text -> t m (BlobOid (t m), HashSet Text)
- Git: copyCommit :: (Repository m, Repository (t m), MonadTrans t) => CommitOid m -> Maybe Text -> HashSet Text -> t m (CommitOid (t m), HashSet Text)
- Git: copyCommitName :: (Repository m, MonadGit m, Repository n, MonadGit n) => CommitName m -> n (Maybe (CommitName n))
- Git: copyCommitOid :: (Repository m, MonadGit m, Repository n, MonadGit n) => CommitOid m -> n (CommitOid n)
- Git: copyConflict :: (Repository m, MonadGit m, Repository n, MonadGit n) => MergeResult m -> n (MergeResult n)
- Git: copyOid :: (Repository m, Repository n) => Oid m -> n (Oid n)
- Git: copyTree :: (Repository m, Repository (t m), MonadTrans t) => TreeOid m -> HashSet Text -> t m (TreeOid (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: createBlob :: Repository m => BlobContents m -> m (BlobOid m)
- Git: createBlobUtf8 :: Repository m => Text -> m (BlobOid m)
- Git: createCommit :: Repository m => [CommitOid m] -> TreeOid m -> Signature -> Signature -> Text -> Maybe Text -> m (Commit m)
- Git: createReference :: Repository m => Text -> RefTarget m -> m (Reference m)
- Git: createReference_ :: Repository m => Text -> RefTarget m -> m ()
- Git: createTag :: Repository m => CommitOid m -> Signature -> Text -> Text -> m (Tag m)
- Git: createTree :: Repository m => TreeT m a -> m (TreeOid m)
- Git: currentTree :: Repository m => TreeT m (Tree m)
- Git: data Blob m
- Git: data BlobContents m
- Git: data BlobKind
- Git: data Commit m
- Git: data CommitName m
- Git: data GitException
- Git: data MergeResult m
- Git: data MergeStatus
- Git: data ModificationKind
- Git: data ModifiedBuilder m
- Git: data ModifyTreeResult m
- Git: data Object m
- Git: data ObjectOid m
- Git: data PinnedEntry m
- Git: data RefTarget m
- Git: data Reference m
- Git: data RepositoryFactory t m c
- Git: data RepositoryFacts
- Git: data RepositoryOptions
- Git: data Signature
- Git: data Tag m
- Git: data TreeBuilder m
- Git: data TreeEntry m
- Git: data TreeT m a
- Git: defaultOptions :: RepositoryFactory t m c -> !RepositoryOptions
- Git: deleteReference :: Repository m => Text -> m ()
- Git: deleteRepository :: Repository m => m ()
- Git: dropEntry :: Repository m => FilePath -> TreeT m ()
- Git: emptyTreeId :: Text
- Git: existsObject :: Repository m => Oid m -> m Bool
- Git: facts :: Repository m => m RepositoryFacts
- Git: fromModifyTreeResult :: ModifyTreeResult m -> Maybe (TreeEntry m)
- Git: genericPushCommit :: (Repository m, Repository (t m), MonadTrans t) => CommitOid m -> Text -> t m (CommitOid (t m))
- Git: getCommitParents :: Repository m => Commit m -> m [Commit m]
- Git: getEntry :: Repository m => FilePath -> TreeT m (Maybe (TreeEntry m))
- Git: getRepository :: RepositoryFactory t m c -> t m c
- Git: getTreeEntry :: Repository m => Tree m -> FilePath -> m (Maybe (TreeEntry m))
- Git: getTreeEntryOid :: Repository m => TreeEntry m -> Oid m
- Git: hasSymbolicReferences :: RepositoryFacts -> !Bool
- Git: hashContents :: Repository m => BlobContents m -> m (BlobOid 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 Default RepositoryOptions
- Git: instance Default Signature
- Git: instance Enum BlobKind
- Git: instance Enum MergeStatus
- Git: instance Enum ModificationKind
- Git: instance Eq (BlobContents m)
- Git: instance Eq BlobKind
- Git: instance Eq BuilderAction
- Git: instance Eq GitException
- Git: instance Eq MergeStatus
- Git: instance Eq ModificationKind
- Git: instance Eq SHA
- Git: instance Exception GitException
- 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 MergeStatus
- Git: instance Ord ModificationKind
- Git: instance Ord SHA
- Git: instance Read MergeStatus
- Git: instance Read ModificationKind
- Git: instance Read SHA
- Git: instance Repository m => Show (CommitName m)
- Git: instance Repository m => Show (MergeResult m)
- Git: instance Show BlobKind
- Git: instance Show BuilderAction
- Git: instance Show GitException
- Git: instance Show MergeStatus
- Git: instance Show ModificationKind
- Git: instance Show RepositoryFacts
- Git: instance Show SHA
- Git: instance Show Signature
- Git: instance Typeable GitException
- Git: loadObject :: Repository m => ObjectOid m -> m (Object m)
- Git: lookupBlob :: Repository m => BlobOid m -> m (Blob m)
- Git: lookupCommit :: Repository m => CommitOid m -> m (Commit m)
- Git: lookupObject :: Repository m => Text -> m (Object m)
- Git: lookupObjectOid :: Repository m => Text -> m (ObjectOid m)
- Git: lookupReference :: Repository m => Text -> m (Maybe (Reference m))
- Git: lookupTag :: Repository m => TagOid m -> m (Tag m)
- Git: lookupTree :: Repository m => TreeOid m -> m (Tree m)
- Git: mergeCommit :: MergeResult m -> CommitOid m
- Git: mergeConflicts :: MergeResult m -> Map FilePath (ModificationKind, ModificationKind)
- Git: mergeHeadLeft :: MergeResult m -> CommitOid m
- Git: mergeHeadRight :: MergeResult m -> CommitOid m
- Git: mergeStatus :: ModificationKind -> ModificationKind -> MergeStatus
- Git: missingObjects :: Repository m => Maybe (CommitOid m) -> CommitOid m -> m [ObjectOid m]
- Git: mtbBaseTreeOid :: TreeBuilder m -> Maybe (TreeOid 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, TreeOid m)
- Git: mutateTree :: Repository m => Tree m -> TreeT m a -> m (TreeOid m)
- Git: mutateTreeOid :: Repository m => TreeOid m -> TreeT m a -> m (TreeOid m)
- Git: nameOfCommit :: Commit m -> CommitName m
- Git: newTreeBuilder :: Repository m => Maybe (Tree m) -> m (TreeBuilder m)
- Git: newtype SHA
- Git: objectOid :: Repository m => Object m -> Oid m
- Git: objectToObjOid :: Repository m => Object m -> ObjectOid m
- Git: openRepository :: RepositoryFactory t m c -> RepositoryOptions -> m c
- Git: parseObjOid :: Repository m => Text -> m (Tagged o (Oid m))
- Git: parseOid :: Repository m => Text -> m (Oid m)
- Git: pinnedCommit :: PinnedEntry m -> Commit m
- Git: pinnedEntry :: PinnedEntry m -> TreeEntry m
- Git: pinnedOid :: PinnedEntry m -> Oid m
- Git: pushCommit :: (Repository m, MonadTrans t, MonadGit m, MonadGit (t m), Repository m, Repository (t m)) => CommitOid m -> Maybe Text -> Text -> t m (CommitOid (t m))
- Git: putBlob :: Repository m => FilePath -> BlobOid m -> TreeT m ()
- Git: putBlob' :: Repository m => FilePath -> BlobOid m -> BlobKind -> TreeT m ()
- Git: putCommit :: Repository m => FilePath -> CommitOid m -> TreeT m ()
- Git: putEntry :: Repository m => FilePath -> TreeEntry m -> TreeT m ()
- Git: putTree :: Repository m => FilePath -> TreeOid m -> TreeT m ()
- Git: referenceName :: Reference m -> !Text
- Git: referenceTarget :: Reference m -> !(RefTarget m)
- Git: referenceToOid :: Repository m => Maybe Text -> Maybe (Reference m) -> m (Maybe (CommitOid m))
- Git: remoteFetch :: Repository m => Text -> Text -> m ()
- Git: renderCommitName :: Repository m => CommitName m -> Text
- Git: renderObjOid :: IsOid o => Tagged a o -> Text
- Git: renderOid :: IsOid o => o -> Text
- Git: repoAutoCreate :: RepositoryOptions -> !Bool
- Git: repoIsBare :: RepositoryOptions -> !Bool
- Git: repoPath :: RepositoryOptions -> !FilePath
- Git: resolveReference :: Repository m => Text -> m (Maybe (CommitOid m))
- Git: resolveReferenceTree :: Repository m => Text -> m (Maybe (Tree m))
- Git: runRepository :: RepositoryFactory t m c -> forall a. c -> t m a -> m a
- Git: shaToText :: SHA -> Text
- Git: shutdownBackend :: RepositoryFactory t m c -> m ()
- Git: signatureEmail :: Signature -> !Text
- Git: signatureName :: Signature -> !Text
- Git: signatureWhen :: Signature -> !ZonedTime
- Git: startupBackend :: RepositoryFactory t m c -> m ()
- Git: tagCommit :: Tag m -> !(CommitOid m)
- Git: tagOid :: Tag m -> !(TagOid m)
- Git: textToSha :: Monad m => Text -> m SHA
- Git: toModifyTreeResult :: (TreeEntry m -> ModifyTreeResult m) -> Maybe (TreeEntry m) -> ModifyTreeResult m
- Git: traverseCommits :: Repository m => (CommitOid m -> m a) -> CommitOid m -> m [a]
- Git: traverseCommits_ :: Repository m => (CommitOid m -> m ()) -> CommitOid m -> m ()
- Git: traverseEntries :: Repository m => (FilePath -> TreeEntry m -> m a) -> Tree m -> m [a]
- Git: traverseEntries_ :: Repository m => (FilePath -> TreeEntry m -> m a) -> Tree m -> m ()
- Git: traverseObjects :: Repository m => (Oid m -> m a) -> Maybe (CommitOid m) -> m [a]
- Git: traverseObjects_ :: Repository m => (Oid m -> m ()) -> Maybe (CommitOid m) -> m ()
- Git: treeBlobEntries :: Repository m => Tree m -> m [(FilePath, TreeEntry m)]
- Git: treeEntry :: Repository m => Tree m -> TreeEntry m
- Git: treeEntryOid :: TreeEntry m -> !(TreeOid m)
- Git: treeOid :: Repository m => Tree m -> TreeOid m
- Git: type BlobOid m = Tagged (Blob m) (Oid m)
- Git: type ByteSource m = Producer m ByteString
- Git: type CommitOid m = Tagged (Commit m) (Oid m)
- Git: type MonadGit m = (Failure GitException m, Applicative m, MonadIO m, MonadBaseControl IO m)
- Git: type TagOid m = Tagged (Tag m) (Oid m)
- Git: type TreeOid m = Tagged (Tree m) (Oid m)
- Git: untagObjOid :: Repository m => ObjectOid m -> Oid m
- Git: updateReference :: Repository m => Text -> RefTarget m -> m (Reference m)
- Git: updateReference_ :: Repository m => Text -> RefTarget m -> m ()
- Git: withBackendDo :: (MonadIO m, MonadBaseControl IO m) => RepositoryFactory t m a -> m b -> m b
- 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: withNewTree :: Repository m => TreeT m a -> m (a, TreeOid m)
- Git: withRepository :: (Repository (t m), MonadTrans t, MonadBaseControl IO m, MonadIO m) => RepositoryFactory t m c -> FilePath -> t m a -> m a
- Git: withRepository' :: (Repository (t m), MonadTrans t, MonadBaseControl IO m, MonadIO m) => RepositoryFactory t m c -> RepositoryOptions -> t m a -> m a
- Git: withTree :: Repository m => Tree m -> TreeT m a -> m (a, TreeOid m)
- Git: withTreeOid :: Repository m => TreeOid m -> TreeT m a -> m (a, TreeOid m)
- Git: writePackFile :: Repository m => FilePath -> m ()
+ Git.Blob: blobContentsToByteString :: Repository m => BlobContents m -> m ByteString
+ Git.Blob: blobToByteString :: Repository m => Blob m -> m ByteString
+ Git.Blob: catBlob :: Repository m => BlobOid m -> m ByteString
+ Git.Blob: catBlobUtf8 :: Repository m => BlobOid m -> m Text
+ Git.Blob: copyBlob :: (Repository m, Repository (t m), MonadTrans t) => BlobOid m -> HashSet Text -> t m (BlobOid (t m), HashSet Text)
+ Git.Blob: createBlobUtf8 :: Repository m => Text -> m (BlobOid m)
+ Git.Blob: treeBlobEntries :: Repository m => Tree m -> m [(Text, BlobOid m, BlobKind)]
+ Git.Commit: commitTreeEntry :: Repository m => Commit m -> Text -> m (Maybe (TreeEntry m))
+ Git.Commit: copyCommit :: (Repository m, Repository (t m), MonadTrans t) => CommitOid m -> Maybe Text -> HashSet Text -> t m (CommitOid (t m), HashSet Text)
+ Git.Commit: copyCommitOid :: (Repository m, Repository n) => CommitOid m -> n (CommitOid n)
+ Git.Commit: listCommits :: Repository m => Maybe (CommitOid m) -> CommitOid m -> m [CommitOid m]
+ Git.Commit: traverseCommits :: Repository m => (CommitOid m -> m a) -> CommitOid m -> m [a]
+ Git.Commit: traverseCommits_ :: Repository m => (CommitOid m -> m ()) -> CommitOid m -> m ()
+ Git.Commit.Push: genericPushCommit :: (Repository m, Repository (t m), MonadTrans t) => CommitOid m -> Text -> t m (CommitOid (t m))
+ Git.Object: expandTreeObjects :: Repository m => [ObjectOid m] -> m [ObjectOid m]
+ Git.Object: listAllObjects :: Repository m => Maybe (CommitOid m) -> CommitOid m -> m [ObjectOid m]
+ Git.Object: traverseObjects :: Repository m => (ObjectOid m -> m a) -> CommitOid m -> m [a]
+ Git.Object: traverseObjects_ :: Repository m => (ObjectOid m -> m ()) -> CommitOid m -> m ()
+ Git.Reference: referenceToOid :: Repository m => RefTarget m -> m (Maybe (CommitOid m))
+ Git.Reference: resolveReference :: Repository m => Text -> m (Maybe (CommitOid m))
+ Git.Reference: resolveReferenceTree :: Repository m => Text -> m (Maybe (Tree m))
+ Git.Repository: withBackendDo :: (MonadIO m, MonadBaseControl IO m) => RepositoryFactory t m a -> m b -> m b
+ Git.Repository: 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.Repository: 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.Repository: withRepository :: (Repository (t m), MonadTrans t, MonadBaseControl IO m, MonadIO m) => RepositoryFactory t m c -> FilePath -> t m a -> m a
+ Git.Repository: withRepository' :: (Repository (t m), MonadTrans t, MonadBaseControl IO m, MonadIO m) => RepositoryFactory t m c -> RepositoryOptions -> t m a -> m a
+ Git.Tree: copyTree :: (Repository m, Repository (t m), MonadTrans t) => TreeOid m -> HashSet Text -> t m (TreeOid (t m), HashSet Text)
+ Git.Tree: copyTreeEntry :: (Repository m, Repository (t m), MonadTrans t) => TreeEntry m -> HashSet Text -> t m (TreeEntry (t m), HashSet Text)
+ Git.Tree.Builder: BuilderUnchanged :: (TreeBuilder m) -> ModifiedBuilder m
+ Git.Tree.Builder: ModifiedBuilder :: (TreeBuilder m) -> ModifiedBuilder m
+ Git.Tree.Builder: TreeBuilder :: Maybe (TreeOid m) -> HashMap Text (TreeBuilder m) -> (Maybe (Tree m) -> m (TreeBuilder m)) -> (TreeBuilder m -> m (ModifiedBuilder m, TreeOid 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.Tree.Builder: TreeEntryDeleted :: ModifyTreeResult m
+ Git.Tree.Builder: TreeEntryMutated :: (TreeEntry m) -> ModifyTreeResult m
+ Git.Tree.Builder: TreeEntryNotFound :: ModifyTreeResult m
+ Git.Tree.Builder: TreeEntryPersistent :: (TreeEntry m) -> ModifyTreeResult m
+ Git.Tree.Builder: createTree :: Repository m => TreeT m a -> m (TreeOid m)
+ Git.Tree.Builder: currentTree :: Repository m => TreeT m (Tree m)
+ Git.Tree.Builder: data ModifiedBuilder m
+ Git.Tree.Builder: data ModifyTreeResult m
+ Git.Tree.Builder: data TreeBuilder m
+ Git.Tree.Builder: data TreeT m a
+ Git.Tree.Builder: dropEntry :: Repository m => Text -> TreeT m ()
+ Git.Tree.Builder: emptyTreeId :: Text
+ Git.Tree.Builder: fromModifyTreeResult :: ModifyTreeResult m -> Maybe (TreeEntry m)
+ Git.Tree.Builder: getEntry :: Repository m => Text -> TreeT m (Maybe (TreeEntry m))
+ Git.Tree.Builder: instance (Functor m, Monad m) => Applicative (TreeT m)
+ Git.Tree.Builder: instance (Functor m, MonadPlus m) => Alternative (TreeT m)
+ Git.Tree.Builder: instance Eq BuilderAction
+ Git.Tree.Builder: instance Functor m => Functor (TreeT m)
+ Git.Tree.Builder: instance Monad m => Monad (TreeT m)
+ Git.Tree.Builder: instance MonadFix m => MonadFix (TreeT m)
+ Git.Tree.Builder: instance MonadIO m => MonadIO (TreeT m)
+ Git.Tree.Builder: instance MonadPlus m => MonadPlus (TreeT m)
+ Git.Tree.Builder: instance MonadTrans TreeT
+ Git.Tree.Builder: instance Show BuilderAction
+ Git.Tree.Builder: mtbBaseTreeOid :: TreeBuilder m -> Maybe (TreeOid m)
+ Git.Tree.Builder: mtbDropEntry :: TreeBuilder m -> TreeBuilder m -> Text -> m (ModifiedBuilder m)
+ Git.Tree.Builder: mtbEntryCount :: TreeBuilder m -> m Int
+ Git.Tree.Builder: mtbLookupEntry :: TreeBuilder m -> Text -> m (Maybe (TreeEntry m))
+ Git.Tree.Builder: mtbNewBuilder :: TreeBuilder m -> Maybe (Tree m) -> m (TreeBuilder m)
+ Git.Tree.Builder: mtbPendingUpdates :: TreeBuilder m -> HashMap Text (TreeBuilder m)
+ Git.Tree.Builder: mtbPutEntry :: TreeBuilder m -> TreeBuilder m -> Text -> TreeEntry m -> m (ModifiedBuilder m)
+ Git.Tree.Builder: mtbWriteContents :: TreeBuilder m -> TreeBuilder m -> m (ModifiedBuilder m, TreeOid m)
+ Git.Tree.Builder: mutateTree :: Repository m => Tree m -> TreeT m a -> m (TreeOid m)
+ Git.Tree.Builder: mutateTreeOid :: Repository m => TreeOid m -> TreeT m a -> m (TreeOid m)
+ Git.Tree.Builder: putBlob :: Repository m => Text -> BlobOid m -> TreeT m ()
+ Git.Tree.Builder: putBlob' :: Repository m => Text -> BlobOid m -> BlobKind -> TreeT m ()
+ Git.Tree.Builder: putCommit :: Repository m => Text -> CommitOid m -> TreeT m ()
+ Git.Tree.Builder: putEntry :: Repository m => Text -> TreeEntry m -> TreeT m ()
+ Git.Tree.Builder: putTree :: Repository m => Text -> TreeOid m -> TreeT m ()
+ Git.Tree.Builder: toModifyTreeResult :: (TreeEntry m -> ModifyTreeResult m) -> Maybe (TreeEntry m) -> ModifyTreeResult m
+ Git.Tree.Builder: treeEntry :: Repository m => Tree m -> Text -> m (Maybe (TreeEntry m))
+ Git.Tree.Builder: withNewTree :: Repository m => TreeT m a -> m (a, TreeOid m)
+ Git.Tree.Builder: withTree :: Repository m => Tree m -> TreeT m a -> m (a, TreeOid m)
+ Git.Tree.Builder: withTreeOid :: Repository m => TreeOid m -> TreeT m a -> m (a, TreeOid m)
+ Git.Tree.Builder.Pure: newPureTreeBuilder :: Repository m => (Tree m -> m (EntryHashMap m)) -> (EntryHashMap m -> m (TreeOid m)) -> Maybe (Tree m) -> m (TreeBuilder m)
+ Git.Tree.Builder.Pure: type EntryHashMap m = HashMap Text (TreeEntry m)
+ Git.Types: Added :: ModificationKind
+ Git.Types: BackendError :: Text -> GitException
+ Git.Types: Blob :: !(BlobOid m) -> !(BlobContents m) -> Blob m
+ Git.Types: BlobCreateFailed :: GitException
+ Git.Types: BlobEmptyCreateFailed :: GitException
+ Git.Types: BlobEncodingUnknown :: Text -> GitException
+ Git.Types: BlobEntry :: !(BlobOid m) -> !BlobKind -> TreeEntry m
+ Git.Types: BlobLookupFailed :: GitException
+ Git.Types: BlobObj :: !(Blob m) -> Object m
+ Git.Types: BlobObjOid :: !(BlobOid m) -> ObjectOid m
+ Git.Types: BlobSizedStream :: !(ByteSource m) -> !Int -> BlobContents m
+ Git.Types: BlobStream :: !(ByteSource m) -> BlobContents m
+ Git.Types: BlobString :: !ByteString -> BlobContents m
+ Git.Types: BothAdded :: MergeStatus
+ Git.Types: BothModified :: MergeStatus
+ Git.Types: BothTypeChanged :: MergeStatus
+ Git.Types: BuilderUnchanged :: (TreeBuilder m) -> ModifiedBuilder m
+ Git.Types: Commit :: !(CommitOid m) -> ![CommitOid m] -> !(TreeOid m) -> !Signature -> !Signature -> !Text -> !Text -> Commit m
+ Git.Types: CommitCreateFailed :: GitException
+ Git.Types: CommitEntry :: !(CommitOid m) -> TreeEntry m
+ Git.Types: CommitLookupFailed :: Text -> GitException
+ Git.Types: CommitObj :: !(Commit m) -> Object m
+ Git.Types: CommitObjOid :: !(CommitOid m) -> ObjectOid m
+ Git.Types: Deleted :: ModificationKind
+ Git.Types: ExecutableBlob :: BlobKind
+ Git.Types: GitError :: Text -> GitException
+ Git.Types: LeftDeletedRightModified :: MergeStatus
+ Git.Types: LeftDeletedRightTypeChanged :: MergeStatus
+ Git.Types: LeftModifiedRightDeleted :: MergeStatus
+ Git.Types: LeftModifiedRightTypeChanged :: MergeStatus
+ Git.Types: LeftTypeChangedRightDeleted :: MergeStatus
+ Git.Types: LeftTypeChangedRightModified :: MergeStatus
+ Git.Types: MergeConflicted :: CommitOid m -> CommitOid m -> CommitOid m -> Map Text (ModificationKind, ModificationKind) -> MergeResult m
+ Git.Types: MergeSuccess :: CommitOid m -> MergeResult m
+ Git.Types: Modified :: ModificationKind
+ Git.Types: ModifiedBuilder :: (TreeBuilder m) -> ModifiedBuilder m
+ Git.Types: NoConflict :: MergeStatus
+ Git.Types: ObjectLookupFailed :: Text -> Int -> GitException
+ Git.Types: ObjectRefRequiresFullOid :: GitException
+ Git.Types: OidCopyFailed :: GitException
+ Git.Types: OidParseFailed :: Text -> GitException
+ Git.Types: PlainBlob :: BlobKind
+ Git.Types: PushNotFastForward :: Text -> GitException
+ Git.Types: QuotaHardLimitExceeded :: Int -> Int -> GitException
+ Git.Types: RefCannotCreateFromPartialOid :: GitException
+ Git.Types: RefObj :: !(CommitOid m) -> RefTarget m
+ Git.Types: RefSymbolic :: !Text -> RefTarget m
+ Git.Types: ReferenceCreateFailed :: GitException
+ Git.Types: ReferenceDeleteFailed :: Text -> GitException
+ Git.Types: ReferenceListingFailed :: GitException
+ Git.Types: ReferenceLookupFailed :: Text -> GitException
+ Git.Types: RepositoryCannotAccess :: Text -> GitException
+ Git.Types: RepositoryFactory :: (RepositoryOptions -> m c) -> (forall a. c -> t m a -> m a) -> (c -> m ()) -> t m c -> !RepositoryOptions -> m () -> m () -> RepositoryFactory t m c
+ Git.Types: RepositoryFacts :: !Bool -> RepositoryFacts
+ Git.Types: RepositoryInvalid :: GitException
+ Git.Types: RepositoryNotExist :: GitException
+ Git.Types: RepositoryOptions :: !FilePath -> !Bool -> !Bool -> RepositoryOptions
+ Git.Types: SHA :: ByteString -> SHA
+ Git.Types: Signature :: !Text -> !Text -> !ZonedTime -> Signature
+ Git.Types: SymlinkBlob :: BlobKind
+ Git.Types: Tag :: !(TagOid m) -> !(CommitOid m) -> Tag m
+ Git.Types: TagObj :: !(Tag m) -> Object m
+ Git.Types: TagObjOid :: !(TagOid m) -> ObjectOid m
+ Git.Types: TranslationException :: Text -> GitException
+ Git.Types: TreeBuilder :: Maybe (TreeOid m) -> HashMap Text (TreeBuilder m) -> (Maybe (Tree m) -> m (TreeBuilder m)) -> (TreeBuilder m -> m (ModifiedBuilder m, TreeOid 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.Types: TreeBuilderCreateFailed :: GitException
+ Git.Types: TreeBuilderInsertFailed :: Text -> GitException
+ Git.Types: TreeBuilderRemoveFailed :: Text -> GitException
+ Git.Types: TreeBuilderWriteFailed :: Text -> GitException
+ Git.Types: TreeCannotTraverseBlob :: GitException
+ Git.Types: TreeCannotTraverseCommit :: GitException
+ Git.Types: TreeCreateFailed :: Text -> GitException
+ Git.Types: TreeEmptyCreateFailed :: GitException
+ Git.Types: TreeEntry :: !(TreeOid m) -> TreeEntry m
+ Git.Types: TreeEntryLookupFailed :: Text -> GitException
+ Git.Types: TreeLookupFailed :: GitException
+ Git.Types: TreeObj :: !(Tree m) -> Object m
+ Git.Types: TreeObjOid :: !(TreeOid m) -> ObjectOid m
+ Git.Types: TreeUpdateFailed :: GitException
+ Git.Types: TreeWalkFailed :: GitException
+ Git.Types: TypeChanged :: ModificationKind
+ Git.Types: Unchanged :: ModificationKind
+ Git.Types: UnknownBlob :: BlobKind
+ Git.Types: blobContents :: Blob m -> !(BlobContents m)
+ Git.Types: blobEntryKind :: TreeEntry m -> !BlobKind
+ Git.Types: blobEntryOid :: TreeEntry m -> !(BlobOid m)
+ Git.Types: blobOid :: Blob m -> !(BlobOid m)
+ Git.Types: buildPackFile :: Repository m => FilePath -> [Either (CommitOid m) (TreeOid m)] -> m FilePath
+ Git.Types: buildPackIndex :: Repository m => FilePath -> ByteString -> m (Text, FilePath, FilePath)
+ Git.Types: class (Eq o, Ord o, Show o) => IsOid o where renderOid = renderObjOid . Tagged renderObjOid = renderOid . untag
+ Git.Types: 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 :: * 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.Types: closeRepository :: RepositoryFactory t m c -> c -> m ()
+ Git.Types: commitAuthor :: Commit m -> !Signature
+ Git.Types: commitCommitter :: Commit m -> !Signature
+ Git.Types: commitEncoding :: Commit m -> !Text
+ Git.Types: commitEntryOid :: TreeEntry m -> !(CommitOid m)
+ Git.Types: commitLog :: Commit m -> !Text
+ Git.Types: commitOid :: Commit m -> !(CommitOid m)
+ Git.Types: commitParents :: Commit m -> ![CommitOid m]
+ Git.Types: commitRefTarget :: Commit m -> RefTarget m
+ Git.Types: commitTree :: Commit m -> !(TreeOid m)
+ Git.Types: copyMergeResult :: (Repository m, MonadGit m, Repository n, MonadGit n) => MergeResult m -> n (MergeResult n)
+ Git.Types: copyOid :: (Repository m, Repository n) => Oid m -> n (Oid n)
+ Git.Types: createBlob :: Repository m => BlobContents m -> m (BlobOid m)
+ Git.Types: createCommit :: Repository m => [CommitOid m] -> TreeOid m -> Signature -> Signature -> Text -> Maybe Text -> m (Commit m)
+ Git.Types: createReference :: Repository m => Text -> RefTarget m -> m ()
+ Git.Types: createTag :: Repository m => CommitOid m -> Signature -> Text -> Text -> m (Tag m)
+ Git.Types: data Blob m
+ Git.Types: data BlobContents m
+ Git.Types: data BlobKind
+ Git.Types: data Commit m
+ Git.Types: data GitException
+ Git.Types: data MergeResult m
+ Git.Types: data MergeStatus
+ Git.Types: data ModificationKind
+ Git.Types: data ModifiedBuilder m
+ Git.Types: data Object m
+ Git.Types: data ObjectOid m
+ Git.Types: data RefTarget m
+ Git.Types: data RepositoryFactory t m c
+ Git.Types: data RepositoryFacts
+ Git.Types: data RepositoryOptions
+ Git.Types: data Signature
+ Git.Types: data Tag m
+ Git.Types: data TreeBuilder m
+ Git.Types: data TreeEntry m
+ Git.Types: defaultOptions :: RepositoryFactory t m c -> !RepositoryOptions
+ Git.Types: deleteReference :: Repository m => Text -> m ()
+ Git.Types: deleteRepository :: Repository m => m ()
+ Git.Types: existsObject :: Repository m => Oid m -> m Bool
+ Git.Types: facts :: Repository m => m RepositoryFacts
+ Git.Types: fromBuilderMod :: ModifiedBuilder m -> TreeBuilder m
+ Git.Types: getRepository :: RepositoryFactory t m c -> t m c
+ Git.Types: hasSymbolicReferences :: RepositoryFacts -> !Bool
+ Git.Types: hashContents :: Repository m => BlobContents m -> m (BlobOid m)
+ Git.Types: instance Binary SHA
+ Git.Types: instance Default RepositoryOptions
+ Git.Types: instance Default Signature
+ Git.Types: instance Enum BlobKind
+ Git.Types: instance Enum MergeStatus
+ Git.Types: instance Enum ModificationKind
+ Git.Types: instance Eq (BlobContents m)
+ Git.Types: instance Eq BlobKind
+ Git.Types: instance Eq GitException
+ Git.Types: instance Eq MergeStatus
+ Git.Types: instance Eq ModificationKind
+ Git.Types: instance Eq SHA
+ Git.Types: instance Exception GitException
+ Git.Types: instance Hashable SHA
+ Git.Types: instance IsOid SHA
+ Git.Types: instance Monoid (ModifiedBuilder m)
+ Git.Types: instance Ord MergeStatus
+ Git.Types: instance Ord ModificationKind
+ Git.Types: instance Ord SHA
+ Git.Types: instance Read MergeStatus
+ Git.Types: instance Read ModificationKind
+ Git.Types: instance Read SHA
+ Git.Types: instance Repository m => Show (MergeResult m)
+ Git.Types: instance Repository m => Show (TreeEntry m)
+ Git.Types: instance Show BlobKind
+ Git.Types: instance Show GitException
+ Git.Types: instance Show MergeStatus
+ Git.Types: instance Show ModificationKind
+ Git.Types: instance Show RepositoryFacts
+ Git.Types: instance Show SHA
+ Git.Types: instance Show Signature
+ Git.Types: instance Typeable GitException
+ Git.Types: listObjects :: Repository m => Maybe (CommitOid m) -> CommitOid m -> Bool -> m [ObjectOid m]
+ Git.Types: listReferences :: Repository m => m [Text]
+ Git.Types: listTreeEntries :: Repository m => Tree m -> m [(Text, TreeEntry m)]
+ Git.Types: loadObject :: Repository m => ObjectOid m -> m (Object m)
+ Git.Types: lookupBlob :: Repository m => BlobOid m -> m (Blob m)
+ Git.Types: lookupCommit :: Repository m => CommitOid m -> m (Commit m)
+ Git.Types: lookupCommitParents :: Repository m => Commit m -> m [Commit m]
+ Git.Types: lookupObject :: Repository m => Oid m -> m (Object m)
+ Git.Types: lookupReference :: Repository m => Text -> m (Maybe (RefTarget m))
+ Git.Types: lookupTag :: Repository m => TagOid m -> m (Tag m)
+ Git.Types: lookupTree :: Repository m => TreeOid m -> m (Tree m)
+ Git.Types: mergeCommit :: MergeResult m -> CommitOid m
+ Git.Types: mergeConflicts :: MergeResult m -> Map Text (ModificationKind, ModificationKind)
+ Git.Types: mergeHeadLeft :: MergeResult m -> CommitOid m
+ Git.Types: mergeHeadRight :: MergeResult m -> CommitOid m
+ Git.Types: mergeStatus :: ModificationKind -> ModificationKind -> MergeStatus
+ Git.Types: mtbBaseTreeOid :: TreeBuilder m -> Maybe (TreeOid m)
+ Git.Types: mtbDropEntry :: TreeBuilder m -> TreeBuilder m -> Text -> m (ModifiedBuilder m)
+ Git.Types: mtbEntryCount :: TreeBuilder m -> m Int
+ Git.Types: mtbLookupEntry :: TreeBuilder m -> Text -> m (Maybe (TreeEntry m))
+ Git.Types: mtbNewBuilder :: TreeBuilder m -> Maybe (Tree m) -> m (TreeBuilder m)
+ Git.Types: mtbPendingUpdates :: TreeBuilder m -> HashMap Text (TreeBuilder m)
+ Git.Types: mtbPutEntry :: TreeBuilder m -> TreeBuilder m -> Text -> TreeEntry m -> m (ModifiedBuilder m)
+ Git.Types: mtbWriteContents :: TreeBuilder m -> TreeBuilder m -> m (ModifiedBuilder m, TreeOid m)
+ Git.Types: newTreeBuilder :: Repository m => Maybe (Tree m) -> m (TreeBuilder m)
+ Git.Types: newtype SHA
+ Git.Types: objectOid :: Repository m => Object m -> Oid m
+ Git.Types: objectToObjOid :: Repository m => Object m -> ObjectOid m
+ Git.Types: openRepository :: RepositoryFactory t m c -> RepositoryOptions -> m c
+ Git.Types: parseObjOid :: Repository m => forall o. Text -> m (Tagged o (Oid m))
+ Git.Types: parseOid :: Repository m => Text -> m (Oid m)
+ Git.Types: pushCommit :: (Repository m, MonadTrans t, MonadGit m, MonadGit (t m), Repository m, Repository (t m)) => CommitOid m -> Maybe Text -> Text -> t m (CommitOid (t m))
+ Git.Types: remoteFetch :: Repository m => Text -> Text -> m ()
+ Git.Types: renderObjOid :: IsOid o => Tagged a o -> Text
+ Git.Types: renderOid :: IsOid o => o -> Text
+ Git.Types: repoAutoCreate :: RepositoryOptions -> !Bool
+ Git.Types: repoIsBare :: RepositoryOptions -> !Bool
+ Git.Types: repoPath :: RepositoryOptions -> !FilePath
+ Git.Types: runRepository :: RepositoryFactory t m c -> forall a. c -> t m a -> m a
+ Git.Types: shaToText :: SHA -> Text
+ Git.Types: shutdownBackend :: RepositoryFactory t m c -> m ()
+ Git.Types: signatureEmail :: Signature -> !Text
+ Git.Types: signatureName :: Signature -> !Text
+ Git.Types: signatureWhen :: Signature -> !ZonedTime
+ Git.Types: startupBackend :: RepositoryFactory t m c -> m ()
+ Git.Types: tagCommit :: Tag m -> !(CommitOid m)
+ Git.Types: tagOid :: Tag m -> !(TagOid m)
+ Git.Types: textToSha :: Monad m => Text -> m SHA
+ Git.Types: treeEntry :: Repository m => Tree m -> Text -> m (Maybe (TreeEntry m))
+ Git.Types: treeEntryOid :: TreeEntry m -> !(TreeOid m)
+ Git.Types: treeEntryToOid :: Repository m => TreeEntry m -> Oid m
+ Git.Types: treeOid :: Repository m => Tree m -> TreeOid m
+ Git.Types: type BlobOid m = Tagged (Blob m) (Oid m)
+ Git.Types: type ByteSource m = Producer m ByteString
+ Git.Types: type CommitOid m = Tagged (Commit m) (Oid m)
+ Git.Types: type MonadGit m = (Failure GitException m, Applicative m, MonadIO m, MonadBaseControl IO m)
+ Git.Types: type TagOid m = Tagged (Tag m) (Oid m)
+ Git.Types: type TreeOid m = Tagged (Tree m) (Oid m)
+ Git.Types: untagObjOid :: Repository m => ObjectOid m -> Oid m
+ Git.Types: updateReference :: Repository m => Text -> RefTarget m -> m ()
+ Git.Types: writePackFile :: Repository m => FilePath -> m ()
Files
- Git.hs +13/−1215
- Git/Blob.hs +61/−0
- Git/Commit.hs +69/−0
- Git/Commit/Push.hs +46/−0
- Git/Object.hs +36/−0
- Git/Reference.hs +21/−0
- Git/Repository.hs +79/−0
- Git/Tree.hs +55/−0
- Git/Tree/Builder.hs +293/−0
- Git/Tree/Builder/Pure.hs +70/−0
- Git/Types.hs +427/−0
- gitlib.cabal +30/−12
- test/Doctest.hs +0/−30
Git.hs view
@@ -1,1215 +1,13 @@-{-# LANGUAGE ConstraintKinds #-}-{-# LANGUAGE DeriveDataTypeable #-}-{-# LANGUAGE EmptyDataDecls #-}-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE MultiParamTypeClasses #-}-{-# LANGUAGE RankNTypes #-}-{-# LANGUAGE RecordWildCards #-}-{-# LANGUAGE TypeFamilies #-}-{-# LANGUAGE ViewPatterns #-}---- | Interface for working with Git repositories.-module Git- ( RepositoryFacts(..)- , Repository(..)- , RepositoryFactory(..)- , RepositoryOptions(..)- , withBackendDo- , withRepository- , withRepository'- , MonadGit-- , IsOid(..)- , copyOid- , Object(..)- , ObjectOid(..)- , objectOid- , loadObject- , objectToObjOid- , untagObjOid- , SHA(..)- , textToSha- , shaToText-- , Blob(..)- , BlobOid- , BlobContents(..)- , BlobKind(..)- , ByteSource- , blobEntry- , createBlobUtf8- , catBlob- , catBlobUtf8- , copyBlob- , blobContentsToByteString- , blobToByteString-- , TreeT- , TreeBuilder(..)- , ModifiedBuilder(..)- , TreeEntry(..)- , TreeOid- , createTree- , withNewTree- , mutateTree- , mutateTreeOid- , currentTree- , withTree- , withTreeOid- , dropEntry- , getEntry- , putBlob- , putBlob'- , putCommit- , putEntry- , putTree- , treeEntry- , getTreeEntryOid- , ModifyTreeResult(..)- , fromModifyTreeResult- , toModifyTreeResult- , emptyTreeId- , treeBlobEntries- , copyTreeEntry- , copyTree-- , Commit(..)- , CommitOid- , CommitName(..)- , Signature(..)- , commitEntry- , commitRefTarget- , getCommitParents- , copyCommitName- , copyCommitOid- , nameOfCommit- , commitNameToOid- , renderCommitName- , commitTreeEntry- , copyCommit- , genericPushCommit-- , PinnedEntry(..)- , commitHistoryFirstParent- , commitEntryHistory- , identifyEntry-- , Tag(..)- , TagOid-- , RefTarget(..)- , Reference(..)- , referenceToOid- , resolveReferenceTree-- , GitException(..)- , ModificationKind(..)- , MergeStatus(..)- , MergeResult(..)- , mergeStatus- , copyConflict- , allMissingObjects- , withNewRepository- , withNewRepository'- ) where--import Control.Applicative-import qualified Control.Exception.Lifted as Exc-import Control.Failure-import Control.Monad-import Control.Monad.Fix-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 (removeTree, isDirectory)-import Filesystem.Path.CurrentOS hiding (null, concat)-import Prelude hiding (FilePath)-import System.Mem (performGC)--{- $repositories -}-data RepositoryFacts = RepositoryFacts- { hasSymbolicReferences :: !Bool- } deriving Show--type MonadGit m = (Failure Git.GitException m, Applicative m,- MonadIO m, MonadBaseControl IO m)--class (Eq o, Ord o, Show o) => IsOid o where- renderOid :: o -> Text- renderOid = renderObjOid . Tagged- renderObjOid :: Tagged a o -> Text- 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 :: *- data Tree m :: *- data Options m :: *-- facts :: m RepositoryFacts-- parseOid :: Text -> m (Oid m)- parseObjOid :: forall o. Text -> m (Tagged o (Oid m))- parseObjOid sha = Tagged <$> parseOid sha-- -- References- createReference :: Text -> RefTarget m -> m (Reference m)- createReference_ :: Text -> RefTarget m -> m ()- createReference_ = (void .) . createReference- lookupReference :: Text -> m (Maybe (Reference m))- updateReference :: Text -> RefTarget m -> m (Reference m)- updateReference_ :: Text -> RefTarget m -> m ()- updateReference_ = (void .) . updateReference- deleteReference :: Text -> m ()-- allReferences :: m [Reference m]- allReferences = catMaybes <$> (mapM lookupReference =<< allReferenceNames)-- allReferenceNames :: m [Text]- allReferenceNames = map referenceName <$> allReferences-- resolveReference :: Text -> m (Maybe (CommitOid m))- resolveReference name = lookupReference name >>= referenceToOid (Just name)-- -- Lookup- lookupCommit :: CommitOid m -> m (Commit m)- lookupTree :: TreeOid m -> m (Tree m)- lookupBlob :: BlobOid m -> m (Blob m)- lookupTag :: TagOid m -> m (Tag m)-- lookupObject :: Text -> m (Object m)- lookupObjectOid :: Text -> m (ObjectOid m)- lookupObjectOid = fmap objectToObjOid . lookupObject- existsObject :: Oid m -> m Bool-- traverseObjects :: forall a.- (Oid m -> m a) -> Maybe (CommitOid m) -> m [a]- traverseObjects_ :: (Oid m -> m ()) -> Maybe (CommitOid m) -> m ()- traverseObjects_ = (void .) . traverseObjects-- pushCommit :: (MonadTrans t, MonadGit m, MonadGit (t m),- Repository m, Repository (t m))- => CommitOid m -> Maybe Text -> Text -> t m (CommitOid (t m))-- traverseCommits :: forall a.- (CommitOid m -> m a) -> CommitOid m -> m [a]- traverseCommits_ :: (CommitOid m -> m ()) -> CommitOid m -> m ()- traverseCommits_ = (void .) . traverseCommits-- missingObjects :: Maybe (CommitOid m) -- ^ A commit we may already have- -> CommitOid m -- ^ The commit we need- -> m [ObjectOid m] -- ^ All the objects in between-- -- Object creation, not to be called by users directly- newTreeBuilder :: Maybe (Tree m) -> m (TreeBuilder 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)- createCommit :: [CommitOid m] -> TreeOid m- -> Signature -> Signature -> Text -> Maybe Text -> m (Commit m)- createTag :: CommitOid m -> Signature -> Text -> Text -> m (Tag m)-- deleteRepository :: m ()-- -- Pack files- buildPackFile :: FilePath -> [Either (CommitOid m) (TreeOid m)]- -> m FilePath- buildPackFile _ _ =- failure (BackendError "Backend does not support building pack files")-- buildPackIndex :: FilePath -> ByteString -> m (Text, FilePath, FilePath)- buildPackIndex _ _ =- failure (BackendError "Backend does not support building pack indexes")-- writePackFile :: FilePath -> m ()- writePackFile _ =- failure (BackendError "Backend does not support writing pack files")-- -- Git remotes- remoteFetch :: Text {- URI -} -> Text {- fetch spec -} -> m ()--{- $exceptions -}--- | There is a separate 'GitException' for each possible failure when--- interacting with the Git repository.-data GitException = BackendError Text- | GitError Text- | RepositoryNotExist- | RepositoryInvalid- | RepositoryCannotAccess Text- | BlobCreateFailed- | BlobEmptyCreateFailed- | BlobEncodingUnknown Text- | BlobLookupFailed- | PushNotFastForward Text- | TranslationException Text- | TreeCreateFailed Text- | TreeBuilderCreateFailed- | TreeBuilderInsertFailed Text- | TreeBuilderRemoveFailed Text- | TreeBuilderWriteFailed Text- | TreeLookupFailed- | TreeCannotTraverseBlob- | TreeCannotTraverseCommit- | TreeEntryLookupFailed FilePath- | TreeUpdateFailed- | TreeWalkFailed- | CommitCreateFailed- | CommitLookupFailed Text- | ReferenceCreateFailed- | ReferenceDeleteFailed Text- | RefCannotCreateFromPartialOid- | ReferenceListingFailed- | ReferenceLookupFailed Text- | ObjectLookupFailed Text Int- | ObjectRefRequiresFullOid- | OidCopyFailed- | OidParseFailed Text- | QuotaHardLimitExceeded Int Int- deriving (Eq, Show, Typeable)---- jww (2013-02-11): Create a BackendException data constructor of forall--- e. Exception e => BackendException e, so that each can throw a derived--- exception.-instance Exc.Exception GitException--{- $oids -}-type BlobOid m = Tagged (Blob 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)--{- $references -}-data RefTarget m = RefObj !(CommitOid m) | RefSymbolic !Text--data Reference m = Reference- { referenceName :: !Text- , referenceTarget :: !(RefTarget m) }--data CommitName m = CommitObjectId !(CommitOid m)- | CommitReferenceName !Text- | CommitReference !(Reference m)--instance Repository m => Show (CommitName m) where- show (CommitObjectId coid) = T.unpack (renderObjOid coid)- show (CommitReferenceName name) = show name- show (CommitReference ref) = show (referenceName ref)--nameOfCommit :: Commit m -> CommitName m-nameOfCommit = CommitObjectId . commitOid--commitNameToOid :: Repository m => CommitName m -> m (Maybe (CommitOid m))-commitNameToOid (CommitObjectId coid) = return (Just coid)-commitNameToOid (CommitReferenceName name) = resolveReference name-commitNameToOid (CommitReference ref) = referenceToOid Nothing (Just ref)--renderCommitName :: Repository m => CommitName m -> Text-renderCommitName (CommitObjectId coid) = renderObjOid coid-renderCommitName (CommitReferenceName name) = name-renderCommitName (CommitReference ref) = referenceName ref--copyOid :: (Repository m, Repository n) => Oid m -> n (Oid n)-copyOid = parseOid . renderOid--copyCommitOid :: (Repository m, MonadGit m, Repository n, MonadGit n)- => CommitOid m -> n (CommitOid n)-copyCommitOid coid = do- ncoid <- parseOid (renderObjOid coid)- return (Tagged ncoid)--copyCommitName :: (Repository m, MonadGit m, Repository n, MonadGit n)- => CommitName m -> n (Maybe (CommitName n))-copyCommitName (CommitObjectId coid) =- Just . CommitObjectId . Tagged <$> parseOid (renderObjOid coid)-copyCommitName (CommitReferenceName name) =- return (Just (CommitReferenceName name))-copyCommitName (CommitReference ref) =- fmap CommitReference <$> lookupReference (referenceName ref)--{- $objects -}-data ObjectOid m = BlobObjOid !(BlobOid m)- | TreeObjOid !(TreeOid m)- | CommitObjOid !(CommitOid m)- | TagObjOid !(TagOid m)--data Object m = BlobObj !(Blob m)- | TreeObj !(Tree m)- | CommitObj !(Commit m)- | TagObj !(Tag m)--objectOid :: Repository m => Object m -> Oid m-objectOid (BlobObj obj) = untag (blobOid obj)-objectOid (TreeObj obj) = untag (treeOid obj)-objectOid (CommitObj obj) = untag (commitOid obj)-objectOid (TagObj obj) = untag (tagOid obj)--loadObject :: Repository m => ObjectOid m -> m (Object m)-loadObject (BlobObjOid oid) = BlobObj <$> lookupBlob oid-loadObject (TreeObjOid oid) = TreeObj <$> lookupTree oid-loadObject (CommitObjOid oid) = CommitObj <$> lookupCommit oid-loadObject (TagObjOid oid) = TagObj <$> lookupTag oid--objectToObjOid :: Repository m => Object m -> ObjectOid m-objectToObjOid (BlobObj obj) = BlobObjOid (blobOid obj)-objectToObjOid (TreeObj obj) = TreeObjOid (treeOid obj)-objectToObjOid (CommitObj obj) = CommitObjOid (commitOid obj)-objectToObjOid (TagObj obj) = TagObjOid (tagOid obj)--untagObjOid :: Repository m => ObjectOid m -> Oid m-untagObjOid (BlobObjOid oid) = untag oid-untagObjOid (TreeObjOid oid) = untag oid-untagObjOid (CommitObjOid oid) = untag oid-untagObjOid (TagObjOid oid) = untag oid--{- $blobs -}-data Blob m = Blob { blobOid :: !(BlobOid m)- , blobContents :: !(BlobContents m) }--type ByteSource m = Producer m ByteString--data BlobContents m = BlobString !ByteString- | BlobStream !(ByteSource m)- | BlobSizedStream !(ByteSource m) !Int--data BlobKind = PlainBlob | ExecutableBlob | SymlinkBlob | UnknownBlob- deriving (Show, Eq, Enum)--instance Eq (BlobContents m) where- BlobString str1 == BlobString str2 = str1 == str2- _ == _ = False--{- $trees -}-newtype TreeT m a = TreeT { runTreeT :: StateT (TreeBuilder m) m a }--instance Functor m => Functor (TreeT m) where- fmap f (TreeT t) = TreeT (fmap f t)--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 m) where- pure = return- (<*>) = ap--instance (Functor m, MonadPlus m) => Alternative (TreeT m) where- empty = mzero- (<|>) = mplus--instance (MonadPlus m) => MonadPlus (TreeT m) where- mzero = TreeT $ mzero- m `mplus` n = TreeT $ runTreeT m `mplus` runTreeT n--instance (MonadFix m) => MonadFix (TreeT m) where- mfix f = TreeT $ mfix $ \ ~a -> runTreeT (f a)--instance MonadTrans TreeT where- lift m = TreeT $ lift m--instance (MonadIO m) => MonadIO (TreeT m) where- liftIO = lift . liftIO--getBuilder :: Monad m => TreeT m (TreeBuilder m)-getBuilder = TreeT get--putBuilder :: Monad m => TreeBuilder m -> TreeT m ()-putBuilder = TreeT . put--data BuilderAction = GetEntry | PutEntry | DropEntry- deriving (Eq, Show)--getEntry :: Repository m => FilePath -> TreeT m (Maybe (TreeEntry m))-getEntry path = do- tb <- getBuilder- snd <$> lift (queryTreeBuilder tb path GetEntry- (toModifyTreeResult TreeEntryPersistent))--putEntry :: Repository m => FilePath -> TreeEntry m -> TreeT m ()-putEntry path ent = do- tb <- getBuilder- tb' <- fst <$> lift (queryTreeBuilder tb path PutEntry- (const (TreeEntryMutated ent)))- putBuilder tb'--dropEntry :: Repository m => FilePath -> TreeT m ()-dropEntry path = do- tb <- getBuilder- tb' <- fst <$> lift (queryTreeBuilder tb path DropEntry- (const TreeEntryDeleted))- putBuilder tb'--putBlob' :: Repository m => FilePath -> BlobOid m -> BlobKind -> TreeT m ()-putBlob' path b kind = putEntry path (BlobEntry b kind)--putBlob :: Repository m => FilePath -> BlobOid m -> TreeT m ()-putBlob path b = putBlob' path b PlainBlob--putTree :: Repository m => FilePath -> TreeOid m -> TreeT m ()-putTree path t = putEntry path (TreeEntry t)--putCommit :: Repository m => FilePath -> CommitOid m -> TreeT m ()-putCommit path c = putEntry path (CommitEntry c)--doWithTree :: Repository m => Maybe (Tree m) -> TreeT m a -> m (a, TreeOid m)-doWithTree mtr act =- fst <$> (runStateT (runTreeT go) =<< newTreeBuilder mtr)- where- go = liftM2 (,) act currentTreeOid--withTree :: Repository m => Tree m -> TreeT m a -> m (a, TreeOid m)-withTree tr = doWithTree (Just tr)--withTreeOid :: Repository m => TreeOid m -> TreeT m a -> m (a, TreeOid m)-withTreeOid oid action = do- tree <- lookupTree oid- doWithTree (Just tree) action--mutateTree :: Repository m => Tree m -> TreeT m a -> m (TreeOid m)-mutateTree tr action = snd <$> withTree tr action--mutateTreeOid :: Repository m => TreeOid m -> TreeT m a -> m (TreeOid m)-mutateTreeOid tr action = snd <$> withTreeOid tr action--currentTreeOid :: Repository m => TreeT m (TreeOid m)-currentTreeOid = do- tb <- getBuilder- (tb', toid) <- lift $ writeTreeBuilder tb- putBuilder tb'- return toid--currentTree :: Repository m => TreeT m (Tree m)-currentTree = lift . lookupTree =<< currentTreeOid--withNewTree :: Repository m => TreeT m a -> m (a, TreeOid m)-withNewTree = doWithTree Nothing--createTree :: Repository m => TreeT m a -> m (TreeOid m)-createTree action = snd <$> withNewTree action--data TreeEntry m = BlobEntry { blobEntryOid :: !(BlobOid m)- , blobEntryKind :: !BlobKind }- | TreeEntry { treeEntryOid :: !(TreeOid m) }- | CommitEntry { commitEntryOid :: !(CommitOid m) }--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 => Tree m -> TreeEntry m-treeEntry = TreeEntry . treeOid--commitEntry :: Repository m => Commit m -> TreeEntry m-commitEntry = CommitEntry . commitOid--data ModifyTreeResult m = TreeEntryNotFound- | TreeEntryDeleted- | TreeEntryPersistent (TreeEntry m)- | TreeEntryMutated (TreeEntry m)--fromModifyTreeResult :: ModifyTreeResult m -> Maybe (TreeEntry m)-fromModifyTreeResult TreeEntryNotFound = Nothing-fromModifyTreeResult TreeEntryDeleted = Nothing-fromModifyTreeResult (TreeEntryPersistent x) = Just x-fromModifyTreeResult (TreeEntryMutated x) = Just x--toModifyTreeResult :: (TreeEntry m -> ModifyTreeResult m)- -> Maybe (TreeEntry m)- -> ModifyTreeResult m-toModifyTreeResult _ Nothing = TreeEntryNotFound-toModifyTreeResult f (Just x) = f x--{- $commits -}-data Signature = Signature- { signatureName :: !Text- , signatureEmail :: !Text- , signatureWhen :: !ZonedTime- } deriving Show--instance Default Signature where- def = Signature- { signatureName = T.empty- , signatureEmail = T.empty- , signatureWhen = ZonedTime- { zonedTimeToLocalTime = LocalTime- { localDay = ModifiedJulianDay 0- , localTimeOfDay = TimeOfDay 0 0 0- }- , zonedTimeZone = utc- }- }--data Commit m = Commit- { commitOid :: !(CommitOid m)- , commitParents :: ![CommitOid m]- , commitTree :: !(TreeOid m)- , commitAuthor :: !Signature- , commitCommitter :: !Signature- , commitLog :: !Text- , commitEncoding :: !Text- }--commitRefTarget :: Commit m -> RefTarget m-commitRefTarget = RefObj . commitOid--referenceToOid :: Repository m- => Maybe Text -> Maybe (Reference m)- -> m (Maybe (CommitOid m))-referenceToOid mname mref =- case mref of- Nothing -> return Nothing- Just (Reference { referenceTarget = RefObj x }) ->- return (Just x)- Just ref@(Reference { referenceTarget = RefSymbolic name' }) ->- if fromMaybe name' mname /= name'- then resolveReference name'- else failure (ReferenceLookupFailed (referenceName ref))--{- $tags -}--data Tag m = Tag- { tagOid :: !(TagOid m)- , tagCommit :: !(CommitOid m)- }--{- $merges -}--data ModificationKind = Unchanged | Modified | Added | Deleted | TypeChanged- deriving (Eq, Ord, Enum, Show, Read)--data MergeStatus- = NoConflict- | BothModified- | LeftModifiedRightDeleted- | LeftDeletedRightModified- | BothAdded- | LeftModifiedRightTypeChanged- | LeftTypeChangedRightModified- | LeftDeletedRightTypeChanged- | LeftTypeChangedRightDeleted- | BothTypeChanged- deriving (Eq, Ord, Enum, Show, Read)--mergeStatus :: ModificationKind -> ModificationKind -> MergeStatus-mergeStatus Unchanged Unchanged = NoConflict-mergeStatus Unchanged Modified = NoConflict-mergeStatus Unchanged Added = undefined-mergeStatus Unchanged Deleted = NoConflict-mergeStatus Unchanged TypeChanged = NoConflict--mergeStatus Modified Unchanged = NoConflict-mergeStatus Modified Modified = BothModified-mergeStatus Modified Added = undefined-mergeStatus Modified Deleted = LeftModifiedRightDeleted-mergeStatus Modified TypeChanged = LeftModifiedRightTypeChanged--mergeStatus Added Unchanged = undefined-mergeStatus Added Modified = undefined-mergeStatus Added Added = BothAdded-mergeStatus Added Deleted = undefined-mergeStatus Added TypeChanged = undefined--mergeStatus Deleted Unchanged = NoConflict-mergeStatus Deleted Modified = LeftDeletedRightModified-mergeStatus Deleted Added = undefined-mergeStatus Deleted Deleted = NoConflict-mergeStatus Deleted TypeChanged = LeftDeletedRightTypeChanged--mergeStatus TypeChanged Unchanged = NoConflict-mergeStatus TypeChanged Modified = LeftTypeChangedRightModified-mergeStatus TypeChanged Added = undefined-mergeStatus TypeChanged Deleted = LeftTypeChangedRightDeleted-mergeStatus TypeChanged TypeChanged = BothTypeChanged--data MergeResult m- = MergeSuccess- { mergeCommit :: CommitOid m- }- | MergeConflicted- { mergeCommit :: CommitOid m- , mergeHeadLeft :: CommitOid m- , mergeHeadRight :: CommitOid m- , mergeConflicts :: Map FilePath (ModificationKind, ModificationKind)- }--instance Repository m => Show (MergeResult m) where- show (MergeSuccess mc) = "MergeSuccess (" ++ show mc ++ ")"- show (MergeConflicted mc hl hr cs) =- "MergeResult"- ++ "\n { mergeCommit = " ++ show mc- ++ "\n , mergeHeadLeft = " ++ show hl- ++ "\n , mergeHeadRight = " ++ show hr- ++ "\n , mergeConflicts = " ++ show cs- ++ "\n }"--copyConflict :: (Repository m, MonadGit m, Repository n, MonadGit n)- => MergeResult m -> n (MergeResult n)-copyConflict (MergeSuccess mc) =- MergeSuccess <$> (Tagged <$> parseOid (renderObjOid mc))-copyConflict (MergeConflicted hl hr mc cs) =- MergeConflicted <$> (Tagged <$> parseOid (renderObjOid hl))- <*> (Tagged <$> parseOid (renderObjOid hr))- <*> (Tagged <$> parseOid (renderObjOid mc))- <*> 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 b -> blobToByteString b- _ -> 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- { mtbBaseTreeOid :: Maybe (TreeOid m)- , mtbPendingUpdates :: HashMap Text (TreeBuilder m)- , mtbNewBuilder :: Maybe (Tree m) -> m (TreeBuilder m)- , mtbWriteContents :: TreeBuilder m -> m (ModifiedBuilder m, TreeOid 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- { mtbBaseTreeOid = 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- { mtbBaseTreeOid = mtbBaseTreeOid 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 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 $ case bm' of- ModifiedBuilder _ ->- ModifiedBuilder tb'- { mtbPendingUpdates = HashMap.delete n upds' }- BuilderUnchanged _ ->- 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, TreeOid m)-writeTreeBuilder builder = do- (bm, mtref) <- go (BuilderUnchanged builder)- tref <- case mtref of- Nothing -> parseObjOid emptyTreeId- 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 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 =<< lookupTree (commitTree c)--copyBlob :: (Repository m, Repository (t m), MonadTrans t)- => BlobOid m- -> HashSet Text- -> t m (BlobOid (t m), HashSet Text)-copyBlob blobr needed = do- let oid = untag blobr- sha = renderOid oid- oid2 <- parseOid (renderOid oid)- if HashSet.member sha needed- then do- bs <- lift $ blobToByteString =<< lookupBlob (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 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)- => TreeOid m- -> HashSet Text- -> t m (TreeOid (t m), HashSet Text)-copyTree tr needed = do- let oid = untag tr- sha = renderOid oid- oid2 <- parseOid (renderOid oid)- if HashSet.member sha needed- then do- tree <- lift $ lookupTree 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 (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)- => CommitOid m- -> Maybe Text- -> HashSet Text- -> t m (CommitOid (t m), HashSet Text)-copyCommit cr mref needed = do- let oid = untag cr- sha = renderOid oid- commit <- lift $ lookupCommit 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 coid = commitOid commit'- x = HashSet.delete sha needed''- return $ coid `seq` x `seq` (coid, x)-- else return (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 => [ObjectOid m] -> m [ObjectOid m]-allMissingObjects objs =- fmap concat . forM objs $ \obj -> case obj of- TreeObjOid toid -> do- tr <- lookupTree toid- subobjss <- flip traverseEntries tr $ \_ ent ->- return $ case ent of- BlobEntry oid _ -> [BlobObjOid oid]- TreeEntry oid -> [TreeObjOid 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)- => CommitOid m -> Text -> t m (CommitOid (t m))-genericPushCommit coid remoteRefName = do- mrref <- lookupReference remoteRefName- commits1 <- lift $ traverseCommits crefToSha coid- 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 (Tagged roid))- | otherwise -> do- failure (PushNotFastForward $- "SHA " <> rsha- <> " not found in remote")- Nothing -> return (Just Nothing)- case fastForward of- Nothing -> failure (PushNotFastForward "unexpected")- Just rref -> do- objs <- lift $ allMissingObjects =<< missingObjects rref coid- shas <- mapM (return . renderOid . untagObjOid) objs- (cref,_) <- copyCommit coid Nothing (HashSet.fromList shas)- -- jww (2013-04-18): This is something the user must- -- decide to do- -- updateReference_ remoteRefName (RefObj cref)- return cref- where- referenceSha ref = fmap renderObjOid <$> referenceToOid Nothing (Just ref)- crefToSha cref = return $ renderObjOid cref--commitHistoryFirstParent :: Repository m => Commit m -> m [Commit m]-commitHistoryFirstParent c =- case commitParents c of- [] -> return [c]- (p:_) -> do ps <- commitHistoryFirstParent =<< lookupCommit 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 =<< lookupCommit 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 lookupCommit . commitParents--resolveReferenceTree :: Repository m => Text -> m (Maybe (Tree m))-resolveReferenceTree refName = do- c <- resolveReference refName- case c of- Nothing -> return Nothing- Just c' ->- Just <$> (lookupCommit c' >>= lookupTree . 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- , repoIsBare :: !Bool- , repoAutoCreate :: !Bool- }--instance Default RepositoryOptions where- def = RepositoryOptions "" True True--data RepositoryFactory t m c = RepositoryFactory- { openRepository :: RepositoryOptions -> m c- , runRepository :: forall a. c -> t m a -> m a- , closeRepository :: c -> m ()- , getRepository :: t m c- , defaultOptions :: !RepositoryOptions- , startupBackend :: m ()- , shutdownBackend :: m ()- }--withBackendDo :: (MonadIO m, MonadBaseControl IO m)- => RepositoryFactory t m a -> m b -> m b-withBackendDo fact f = do- startupBackend fact- Exc.finally f (liftIO performGC >> shutdownBackend fact)--withRepository' :: (Repository (t m), MonadTrans t,- MonadBaseControl IO m, MonadIO m)- => RepositoryFactory t m c- -> RepositoryOptions- -> t m a- -> m a-withRepository' factory opts action =- Exc.bracket- (openRepository factory opts)- (closeRepository factory)- (flip (runRepository factory) action)--withRepository :: (Repository (t m), MonadTrans t,- MonadBaseControl IO m, MonadIO m)- => RepositoryFactory t m c- -> FilePath- -> t m a- -> m a-withRepository factory path =- withRepository' factory- (defaultOptions factory) { repoPath = path }---- Git.hs+-- | Interface for working with Git repositories.+module Git+ ( module X+ ) where++import Git.Blob as X+import Git.Commit as X+import Git.Object as X+import Git.Reference as X+import Git.Repository as X+import Git.Tree as X+import Git.Tree.Builder as X+import Git.Types as X
+ Git/Blob.hs view
@@ -0,0 +1,61 @@+module Git.Blob where++import Control.Monad+import Control.Monad.Trans.Class+import Data.ByteString as B+import Data.Conduit+import qualified Data.Conduit.List as CList+import Data.HashSet (HashSet)+import qualified Data.HashSet as HashSet+import Data.Tagged+import Data.Text as T+import Data.Text.Encoding as T+import Git.Types+import Prelude hiding (FilePath)++createBlobUtf8 :: Repository m => Text -> m (BlobOid m)+createBlobUtf8 = createBlob . BlobString . T.encodeUtf8++catBlob :: Repository m => BlobOid m -> m ByteString+catBlob = lookupBlob >=> blobToByteString++catBlobUtf8 :: Repository m => BlobOid m -> 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++treeBlobEntries :: Repository m => Tree m -> m [(Text, BlobOid m, BlobKind)]+treeBlobEntries tree = do+ entries <- listTreeEntries tree+ return $ Prelude.foldr f [] entries+ where+ f (fp ,BlobEntry oid k) xs = (fp, oid, k):xs+ f _ xs = xs++copyBlob :: (Repository m, Repository (t m), MonadTrans t)+ => BlobOid m+ -> HashSet Text+ -> t m (BlobOid (t m), HashSet Text)+copyBlob blobr needed = do+ let oid = untag blobr+ sha = renderOid oid+ oid2 <- parseOid (renderOid oid)+ if HashSet.member sha needed+ then do+ bs <- lift $ blobToByteString =<< lookupBlob (Tagged oid)+ boid <- createBlob (BlobString bs)++ let x = HashSet.delete sha needed+ return $ boid `seq` x `seq` (boid, x)++ else return (Tagged oid2, needed)
+ Git/Commit.hs view
@@ -0,0 +1,69 @@+module Git.Commit where++import Control.Monad+import Control.Monad.Trans.Class+import Data.Function+import Data.HashSet (HashSet)+import qualified Data.HashSet as HashSet+import Data.List+import Data.Maybe+import Data.Tagged+import Data.Text (Text)+import Git.Tree+import Git.Types+import Prelude hiding (FilePath)++commitTreeEntry :: Repository m+ => Commit m+ -> Text+ -> m (Maybe (TreeEntry m))+commitTreeEntry c path = flip treeEntry path =<< lookupTree (commitTree c)++copyCommitOid :: (Repository m, Repository n) => CommitOid m -> n (CommitOid n)+copyCommitOid = parseObjOid . renderObjOid++copyCommit :: (Repository m, Repository (t m), MonadTrans t)+ => CommitOid m+ -> Maybe Text+ -> HashSet Text+ -> t m (CommitOid (t m), HashSet Text)+copyCommit cr mref needed = do+ let oid = untag cr+ sha = renderOid oid+ commit <- lift $ lookupCommit 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 coid = commitOid commit'+ x = HashSet.delete sha needed''+ return $ coid `seq` x `seq` (coid, x)++ else return (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'')++listCommits :: Repository m+ => Maybe (CommitOid m) -- ^ A commit we may already have+ -> CommitOid m -- ^ The commit we need+ -> m [CommitOid m] -- ^ All the objects in between+listCommits have need =+ mapM (\(CommitObjOid c) -> return c) =<< listObjects have need False++traverseCommits :: Repository m => (CommitOid m -> m a) -> CommitOid m -> m [a]+traverseCommits f need = mapM f =<< listCommits Nothing need++traverseCommits_ :: Repository m => (CommitOid m -> m ()) -> CommitOid m -> m ()+traverseCommits_ = (void .) . traverseCommits
+ Git/Commit/Push.hs view
@@ -0,0 +1,46 @@+module Git.Commit.Push where++import Control.Failure+import Control.Monad+import Control.Monad.Trans.Class+import Data.Function+import qualified Data.HashSet as HashSet+import Data.List+import Data.Maybe+import Data.Monoid+import Data.Text (Text)+import Git.Commit+import Git.Reference+import Git.Object+import Git.Types+import Prelude hiding (FilePath)++-- | Fast-forward push a reference between repositories using a recursive+-- copy. This can be extremely slow, but always works no matter which two+-- backends are being used. It should be considered a matter of last+-- resort, or for objects sets that are known to be small.+genericPushCommit :: (Repository m, Repository (t m), MonadTrans t)+ => CommitOid m -> Text -> t m (CommitOid (t m))+genericPushCommit coid remoteRefName = do+ mrref <- resolveReference remoteRefName+ commits1 <- mapM copyCommitOid =<< lift (listCommits Nothing coid)+ fastForward <- case mrref of+ Nothing -> return (Just Nothing)+ Just rref+ | rref `elem` commits1 -> do+ roid <- lift $ copyCommitOid rref+ return $ Just (Just roid)+ | otherwise -> do+ failure (PushNotFastForward $+ "SHA " <> renderObjOid rref+ <> " not found in remote")+ case fastForward of+ Nothing -> failure (PushNotFastForward "unexpected")+ Just rref -> do+ objs <- lift $ listAllObjects rref coid+ shas <- mapM (return . renderOid . untagObjOid) objs+ (cref,_) <- copyCommit coid Nothing (HashSet.fromList shas)+ -- jww (2013-04-18): This is something the user must+ -- decide to do+ -- updateReference_ remoteRefName (RefObj cref)+ return cref
+ Git/Object.hs view
@@ -0,0 +1,36 @@+module Git.Object where++import Control.Monad+import Data.Function+import Data.List+import Data.Maybe+import Git.Types+import Prelude hiding (FilePath)++traverseObjects :: Repository m => (ObjectOid m -> m a) -> CommitOid m -> m [a]+traverseObjects f need = mapM f =<< listObjects Nothing need False++traverseObjects_ :: Repository m => (ObjectOid m -> m ()) -> CommitOid m -> m ()+traverseObjects_ = (void .) . traverseObjects++-- | Given a list of objects (commit and top-level trees) return by+-- 'listObjects', expand it to include all subtrees and blobs as well.+-- Ordering is preserved.+expandTreeObjects :: Repository m => [ObjectOid m] -> m [ObjectOid m]+expandTreeObjects objs =+ fmap concat . forM objs $ \obj -> case obj of+ TreeObjOid toid -> do+ tr <- lookupTree toid+ entries <- listTreeEntries tr+ let subobjss = foldr f [] entries+ return (obj:subobjss)+ _ -> return [obj]+ where+ f (_, ent) rest = case ent of+ BlobEntry oid _ -> BlobObjOid oid : rest+ TreeEntry oid -> TreeObjOid oid : rest+ _ -> rest++listAllObjects :: Repository m+ => Maybe (CommitOid m) -> CommitOid m -> m [ObjectOid m]+listAllObjects have need = expandTreeObjects =<< listObjects have need True
+ Git/Reference.hs view
@@ -0,0 +1,21 @@+module Git.Reference where++import Control.Applicative+import Data.Text+import Git.Types++resolveReference :: Repository m => Text -> m (Maybe (CommitOid m))+resolveReference name = do+ mref <- lookupReference name+ maybe (return Nothing) referenceToOid mref++referenceToOid :: Repository m => RefTarget m -> m (Maybe (CommitOid m))+referenceToOid (RefObj oid) = return $ Just oid+referenceToOid (RefSymbolic name) = resolveReference name++resolveReferenceTree :: Repository m => Text -> m (Maybe (Tree m))+resolveReferenceTree refName = do+ c <- resolveReference refName+ case c of+ Nothing -> return Nothing+ Just c' -> Just <$> (lookupCommit c' >>= lookupTree . commitTree)
+ Git/Repository.hs view
@@ -0,0 +1,79 @@+module Git.Repository where++import qualified Control.Exception.Lifted as Exc+import Control.Monad+import Control.Monad.IO.Class+import Control.Monad.Trans.Class+import Data.Conduit+import Data.Function+import Filesystem+import Filesystem.Path.CurrentOS hiding (null, concat)+import Git.Types+import Prelude hiding (FilePath)+import System.Mem++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+++withBackendDo :: (MonadIO m, MonadBaseControl IO m)+ => RepositoryFactory t m a -> m b -> m b+withBackendDo fact f = do+ startupBackend fact+ Exc.finally f (liftIO performGC >> shutdownBackend fact)++withRepository' :: (Repository (t m), MonadTrans t,+ MonadBaseControl IO m, MonadIO m)+ => RepositoryFactory t m c+ -> RepositoryOptions+ -> t m a+ -> m a+withRepository' factory opts action =+ Exc.bracket+ (openRepository factory opts)+ (closeRepository factory)+ (flip (runRepository factory) action)++withRepository :: (Repository (t m), MonadTrans t,+ MonadBaseControl IO m, MonadIO m)+ => RepositoryFactory t m c+ -> FilePath+ -> t m a+ -> m a+withRepository factory path =+ withRepository' factory+ (defaultOptions factory) { repoPath = path }
+ Git/Tree.hs view
@@ -0,0 +1,55 @@+module Git.Tree where++import Control.Monad+import Control.Monad.Trans.Class+import Data.Function+import Data.HashSet (HashSet)+import qualified Data.HashSet as HashSet+import Data.Tagged+import Data.Text (Text)+import Git.Blob+import Git.Tree.Builder+import Git.Types+import Prelude hiding (FilePath)++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 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)+ => TreeOid m+ -> HashSet Text+ -> t m (TreeOid (t m), HashSet Text)+copyTree tr needed = do+ let oid = untag tr+ sha = renderOid oid+ oid2 <- parseOid (renderOid oid)+ if HashSet.member sha needed+ then do+ tree <- lift $ lookupTree tr+ entries <- lift $ listTreeEntries tree+ (needed', tref) <-+ withNewTree $ foldM doCopyTreeEntry needed entries++ let x = HashSet.delete sha needed'+ return $ tref `seq` x `seq` (tref, x)++ else return (Tagged oid2, needed)+ where+ doCopyTreeEntry :: (Repository m, Repository (t m), MonadTrans t)+ => HashSet Text+ -> (Text, TreeEntry m)+ -> TreeT (t m) (HashSet Text)+ doCopyTreeEntry set (_, TreeEntry {}) = return set+ doCopyTreeEntry set (fp, ent) = do+ (ent2,set') <- lift $ copyTreeEntry ent set+ putEntry fp ent2+ return set'
+ Git/Tree/Builder.hs view
@@ -0,0 +1,293 @@+module Git.Tree.Builder+ ( TreeT+ , TreeBuilder(..)+ , ModifiedBuilder(..)+ , createTree+ , withNewTree+ , mutateTree+ , mutateTreeOid+ , currentTree+ , withTree+ , withTreeOid+ , dropEntry+ , getEntry+ , putBlob+ , putBlob'+ , putCommit+ , putEntry+ , putTree+ , treeEntry+ , ModifyTreeResult(..)+ , fromModifyTreeResult+ , toModifyTreeResult+ , emptyTreeId+ ) where++import Control.Applicative+import Control.Failure+import Control.Monad+import Control.Monad.Fix+import Control.Monad.IO.Class+import Control.Monad.Trans.Class+import Control.Monad.Trans.State+import Data.Function+import qualified Data.HashMap.Strict as HashMap+import Data.List+import Data.Maybe+import Data.Monoid+import Data.Text (Text)+import qualified Data.Text as T+import Git.Types+import Prelude hiding (FilePath)++data ModifyTreeResult m = TreeEntryNotFound+ | TreeEntryDeleted+ | TreeEntryPersistent (TreeEntry m)+ | TreeEntryMutated (TreeEntry m)++fromModifyTreeResult :: ModifyTreeResult m -> Maybe (TreeEntry m)+fromModifyTreeResult TreeEntryNotFound = Nothing+fromModifyTreeResult TreeEntryDeleted = Nothing+fromModifyTreeResult (TreeEntryPersistent x) = Just x+fromModifyTreeResult (TreeEntryMutated x) = Just x++toModifyTreeResult :: (TreeEntry m -> ModifyTreeResult m)+ -> Maybe (TreeEntry m)+ -> ModifyTreeResult m+toModifyTreeResult _ Nothing = TreeEntryNotFound+toModifyTreeResult f (Just x) = f x++newtype TreeT m a = TreeT { runTreeT :: StateT (TreeBuilder m) m a }++instance Functor m => Functor (TreeT m) where+ fmap f (TreeT t) = TreeT (fmap f t)++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 m) where+ pure = return+ (<*>) = ap++instance (Functor m, MonadPlus m) => Alternative (TreeT m) where+ empty = mzero+ (<|>) = mplus++instance (MonadPlus m) => MonadPlus (TreeT m) where+ mzero = TreeT $ mzero+ m `mplus` n = TreeT $ runTreeT m `mplus` runTreeT n++instance (MonadFix m) => MonadFix (TreeT m) where+ mfix f = TreeT $ mfix $ \ ~a -> runTreeT (f a)++instance MonadTrans TreeT where+ lift m = TreeT $ lift m++instance (MonadIO m) => MonadIO (TreeT m) where+ liftIO = lift . liftIO++getBuilder :: Monad m => TreeT m (TreeBuilder m)+getBuilder = TreeT get++putBuilder :: Monad m => TreeBuilder m -> TreeT m ()+putBuilder = TreeT . put++data BuilderAction = GetEntry | PutEntry | DropEntry+ deriving (Eq, Show)++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+ -> Text+ -> 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 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 $ case bm' of+ ModifiedBuilder _ ->+ ModifiedBuilder tb'+ { mtbPendingUpdates = HashMap.delete n upds' }+ BuilderUnchanged _ ->+ 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, TreeOid m)+writeTreeBuilder builder = do+ (bm, mtref) <- go (BuilderUnchanged builder)+ tref <- case mtref of+ Nothing -> parseObjOid emptyTreeId+ 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 tref)+ return $ bm <> bm'++getEntry :: Repository m => Text -> TreeT m (Maybe (TreeEntry m))+getEntry path = do+ tb <- getBuilder+ snd <$> lift (queryTreeBuilder tb path GetEntry+ (toModifyTreeResult TreeEntryPersistent))++putEntry :: Repository m => Text -> TreeEntry m -> TreeT m ()+putEntry path ent = do+ tb <- getBuilder+ tb' <- fst <$> lift (queryTreeBuilder tb path PutEntry+ (const (TreeEntryMutated ent)))+ putBuilder tb'++dropEntry :: Repository m => Text -> TreeT m ()+dropEntry path = do+ tb <- getBuilder+ tb' <- fst <$> lift (queryTreeBuilder tb path DropEntry+ (const TreeEntryDeleted))+ putBuilder tb'++putBlob' :: Repository m => Text -> BlobOid m -> BlobKind -> TreeT m ()+putBlob' path b kind = putEntry path (BlobEntry b kind)++putBlob :: Repository m => Text -> BlobOid m -> TreeT m ()+putBlob path b = putBlob' path b PlainBlob++putTree :: Repository m => Text -> TreeOid m -> TreeT m ()+putTree path t = putEntry path (TreeEntry t)++putCommit :: Repository m => Text -> CommitOid m -> TreeT m ()+putCommit path c = putEntry path (CommitEntry c)++doWithTree :: Repository m => Maybe (Tree m) -> TreeT m a -> m (a, TreeOid m)+doWithTree mtr act =+ fst <$> (runStateT (runTreeT go) =<< newTreeBuilder mtr)+ where+ go = liftM2 (,) act currentTreeOid++withTree :: Repository m => Tree m -> TreeT m a -> m (a, TreeOid m)+withTree tr = doWithTree (Just tr)++withTreeOid :: Repository m => TreeOid m -> TreeT m a -> m (a, TreeOid m)+withTreeOid oid action = do+ tree <- lookupTree oid+ doWithTree (Just tree) action++mutateTree :: Repository m => Tree m -> TreeT m a -> m (TreeOid m)+mutateTree tr action = snd <$> withTree tr action++mutateTreeOid :: Repository m => TreeOid m -> TreeT m a -> m (TreeOid m)+mutateTreeOid tr action = snd <$> withTreeOid tr action++currentTreeOid :: Repository m => TreeT m (TreeOid m)+currentTreeOid = do+ tb <- getBuilder+ (tb', toid) <- lift $ writeTreeBuilder tb+ putBuilder tb'+ return toid++currentTree :: Repository m => TreeT m (Tree m)+currentTree = lift . lookupTree =<< currentTreeOid++withNewTree :: Repository m => TreeT m a -> m (a, TreeOid m)+withNewTree = doWithTree Nothing++createTree :: Repository m => TreeT m a -> m (TreeOid m)+createTree action = snd <$> withNewTree action++splitPath :: Text -> [Text]+splitPath = T.splitOn "/"
+ Git/Tree/Builder/Pure.hs view
@@ -0,0 +1,70 @@+module Git.Tree.Builder.Pure+ ( EntryHashMap+ , newPureTreeBuilder+ ) where++import Control.Applicative+import Data.Monoid+import Data.Text+import Data.HashMap.Strict (HashMap)+import qualified Data.HashMap.Strict as HashMap+import Git++type EntryHashMap m = HashMap Text (TreeEntry m)++-- | Create a new, empty tree.+--+-- Since empty trees cannot exist in Git, attempting to write out an empty+-- tree is a no-op.+newPureTreeBuilder :: Repository m+ => (Tree m -> m (EntryHashMap m))+ -> (EntryHashMap m -> m (TreeOid m))+ -> Maybe (Tree m)+ -> m (TreeBuilder m)+newPureTreeBuilder reader writer mtree = do+ entMap <- case mtree of+ Nothing -> return HashMap.empty+ Just tree -> reader tree+ return $ makePureBuilder+ (treeOid <$> mtree)+ mempty+ (newPureTreeBuilder reader writer)+ entMap+ writer++makePureBuilder :: Repository m+ => Maybe (TreeOid m)+ -> HashMap Text (TreeBuilder m)+ -> (Maybe (Tree m) -> m (TreeBuilder m))+ -> EntryHashMap m+ -> (EntryHashMap m -> m (TreeOid m))+ -> TreeBuilder m+makePureBuilder baseTree upds newBuilder entMap writer = TreeBuilder+ { mtbBaseTreeOid = baseTree+ , mtbPendingUpdates = upds+ , mtbNewBuilder = newBuilder++ , mtbWriteContents = \tb -> (,) <$> pure (BuilderUnchanged tb)+ <*> writer entMap++ , mtbLookupEntry = \key -> return $ HashMap.lookup key entMap+ , mtbEntryCount = return $ HashMap.size entMap++ , mtbPutEntry = \tb key ent ->+ return . ModifiedBuilder $+ makePureBuilder+ baseTree+ (mtbPendingUpdates tb)+ newBuilder+ (HashMap.insert key ent entMap)+ writer++ , mtbDropEntry = \tb key ->+ return . ModifiedBuilder $+ makePureBuilder+ baseTree+ (mtbPendingUpdates tb)+ newBuilder+ (HashMap.delete key entMap)+ writer+ }
+ Git/Types.hs view
@@ -0,0 +1,427 @@+module Git.Types where++import Control.Applicative+import qualified Control.Exception.Lifted as Exc+import Control.Failure+import Control.Monad+import Control.Monad.IO.Class+import Control.Monad.Trans.Class+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 Data.Default+import Data.Function+import Data.HashMap.Strict (HashMap)+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.Typeable+import Filesystem.Path.CurrentOS hiding (null, concat)+import Prelude hiding (FilePath)++data RepositoryFacts = RepositoryFacts+ { hasSymbolicReferences :: !Bool+ } deriving Show++type MonadGit m = (Failure GitException m, Applicative m,+ MonadIO m, MonadBaseControl IO m)++-- | '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 :: *+ data Tree m :: *+ data Options m :: *++ facts :: m RepositoryFacts+ parseOid :: Text -> m (Oid m)+ deleteRepository :: m ()++ -- References+ createReference :: Text -> RefTarget m -> m ()+ lookupReference :: Text -> m (Maybe (RefTarget m))+ updateReference :: Text -> RefTarget m -> m ()+ deleteReference :: Text -> m ()+ listReferences :: m [Text]++ -- Object lookup+ lookupCommit :: CommitOid m -> m (Commit m)+ lookupTree :: TreeOid m -> m (Tree m)+ lookupBlob :: BlobOid m -> m (Blob m)+ lookupTag :: TagOid m -> m (Tag m)+ lookupObject :: Oid m -> m (Object m)+ existsObject :: Oid m -> m Bool+ listObjects :: Maybe (CommitOid m) -- ^ A commit we may already have+ -> CommitOid m -- ^ The commit we need+ -> Bool -- ^ Include commit trees also?+ -> m [ObjectOid m] -- ^ All the objects in between++ -- Working with trees+ newTreeBuilder :: Maybe (Tree m) -> m (TreeBuilder m)++ treeOid :: Tree m -> TreeOid m+ treeEntry :: Tree m -> Text -> m (Maybe (TreeEntry m))+ listTreeEntries :: Tree m -> m [(Text, TreeEntry m)]++ -- Creating other objects+ hashContents :: BlobContents m -> m (BlobOid m)+ createBlob :: BlobContents m -> m (BlobOid m)+ createCommit :: [CommitOid m] -> TreeOid m+ -> Signature -> Signature -> Text -> Maybe Text -> m (Commit m)+ createTag :: CommitOid m -> Signature -> Text -> Text -> m (Tag m)++ -- Pushing and pulling+ pushCommit :: (MonadTrans t, MonadGit m, MonadGit (t m),+ Repository m, Repository (t m))+ => CommitOid m -> Maybe Text -> Text -> t m (CommitOid (t m))++ -- Pack files+ buildPackFile :: FilePath -> [Either (CommitOid m) (TreeOid m)]+ -> m FilePath+ buildPackFile _ _ =+ failure (BackendError "Backend does not support building pack files")++ buildPackIndex :: FilePath -> ByteString -> m (Text, FilePath, FilePath)+ buildPackIndex _ _ =+ failure (BackendError "Backend does not support building pack indexes")++ writePackFile :: FilePath -> m ()+ writePackFile _ =+ failure (BackendError "Backend does not support writing pack files")++ -- Git remotes+ remoteFetch :: Text {- URI -} -> Text {- fetch spec -} -> m ()++data RepositoryOptions = RepositoryOptions+ { repoPath :: !FilePath+ , repoIsBare :: !Bool+ , repoAutoCreate :: !Bool+ }++instance Default RepositoryOptions where+ def = RepositoryOptions "" True True++data RepositoryFactory t m c = RepositoryFactory+ { openRepository :: RepositoryOptions -> m c+ , runRepository :: forall a. c -> t m a -> m a+ , closeRepository :: c -> m ()+ , getRepository :: t m c+ , defaultOptions :: !RepositoryOptions+ , startupBackend :: m ()+ , shutdownBackend :: m ()+ }++{- $oids -}+class (Eq o, Ord o, Show o) => IsOid o where+ renderOid :: o -> Text+ renderOid = renderObjOid . Tagged+ renderObjOid :: Tagged a o -> Text+ renderObjOid = renderOid . untag++type BlobOid m = Tagged (Blob 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)++data ObjectOid m = BlobObjOid !(BlobOid m)+ | TreeObjOid !(TreeOid m)+ | CommitObjOid !(CommitOid m)+ | TagObjOid !(TagOid m)++parseObjOid :: Repository m => forall o. Text -> m (Tagged o (Oid m))+parseObjOid sha = Tagged <$> parseOid sha++copyOid :: (Repository m, Repository n) => Oid m -> n (Oid n)+copyOid = parseOid . renderOid++newtype SHA = SHA B.ByteString deriving (Eq, Ord, Read)++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"++instance IsOid SHA where+ renderOid = shaToText++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++{- $blobs -}+data Blob m = Blob { blobOid :: !(BlobOid m)+ , blobContents :: !(BlobContents m) }++type ByteSource m = Producer m ByteString++data BlobContents m = BlobString !ByteString+ | BlobStream !(ByteSource m)+ | BlobSizedStream !(ByteSource m) !Int++data BlobKind = PlainBlob | ExecutableBlob | SymlinkBlob | UnknownBlob+ deriving (Show, Eq, Enum)++instance Eq (BlobContents m) where+ BlobString str1 == BlobString str2 = str1 == str2+ _ == _ = False++{- $trees -}+data TreeEntry m = BlobEntry { blobEntryOid :: !(BlobOid m)+ , blobEntryKind :: !BlobKind }+ | TreeEntry { treeEntryOid :: !(TreeOid m) }+ | CommitEntry { commitEntryOid :: !(CommitOid m) }++instance Repository m => Show (TreeEntry m) where+ show (BlobEntry oid _) = "<BlobEntry " ++ T.unpack (renderObjOid oid)+ show (TreeEntry oid) = "<TreeEntry " ++ T.unpack (renderObjOid oid)+ show (CommitEntry oid) = "<CommitEntry " ++ T.unpack (renderObjOid oid)++treeEntryToOid :: Repository m => TreeEntry m -> Oid m+treeEntryToOid (BlobEntry boid _) = untag boid+treeEntryToOid (TreeEntry toid) = untag toid+treeEntryToOid (CommitEntry coid) = untag coid++data TreeBuilder m = TreeBuilder+ { mtbBaseTreeOid :: Maybe (TreeOid m)+ , mtbPendingUpdates :: HashMap Text (TreeBuilder m)+ , mtbNewBuilder :: Maybe (Tree m) -> m (TreeBuilder m)+ , mtbWriteContents :: TreeBuilder m -> m (ModifiedBuilder m, TreeOid 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)+ }++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++{- $commits -}+data Commit m = Commit+ { commitOid :: !(CommitOid m)+ , commitParents :: ![CommitOid m]+ , commitTree :: !(TreeOid m)+ , commitAuthor :: !Signature+ , commitCommitter :: !Signature+ , commitLog :: !Text+ , commitEncoding :: !Text+ }++lookupCommitParents :: Repository m => Commit m -> m [Commit m]+lookupCommitParents = mapM lookupCommit . commitParents++data Signature = Signature+ { signatureName :: !Text+ , signatureEmail :: !Text+ , signatureWhen :: !ZonedTime+ } deriving Show++instance Default Signature where+ def = Signature+ { signatureName = T.empty+ , signatureEmail = T.empty+ , signatureWhen = ZonedTime+ { zonedTimeToLocalTime = LocalTime+ { localDay = ModifiedJulianDay 0+ , localTimeOfDay = TimeOfDay 0 0 0+ }+ , zonedTimeZone = utc+ }+ }++{- $tags -}+data Tag m = Tag+ { tagOid :: !(TagOid m)+ , tagCommit :: !(CommitOid m)+ }++{- $objects -}+data Object m = BlobObj !(Blob m)+ | TreeObj !(Tree m)+ | CommitObj !(Commit m)+ | TagObj !(Tag m)++objectOid :: Repository m => Object m -> Oid m+objectOid (BlobObj obj) = untag (blobOid obj)+objectOid (TreeObj obj) = untag (treeOid obj)+objectOid (CommitObj obj) = untag (commitOid obj)+objectOid (TagObj obj) = untag (tagOid obj)++loadObject :: Repository m => ObjectOid m -> m (Object m)+loadObject (BlobObjOid oid) = BlobObj <$> lookupBlob oid+loadObject (TreeObjOid oid) = TreeObj <$> lookupTree oid+loadObject (CommitObjOid oid) = CommitObj <$> lookupCommit oid+loadObject (TagObjOid oid) = TagObj <$> lookupTag oid++objectToObjOid :: Repository m => Object m -> ObjectOid m+objectToObjOid (BlobObj obj) = BlobObjOid (blobOid obj)+objectToObjOid (TreeObj obj) = TreeObjOid (treeOid obj)+objectToObjOid (CommitObj obj) = CommitObjOid (commitOid obj)+objectToObjOid (TagObj obj) = TagObjOid (tagOid obj)++untagObjOid :: Repository m => ObjectOid m -> Oid m+untagObjOid (BlobObjOid oid) = untag oid+untagObjOid (TreeObjOid oid) = untag oid+untagObjOid (CommitObjOid oid) = untag oid+untagObjOid (TagObjOid oid) = untag oid++{- $references -}+data RefTarget m = RefObj !(CommitOid m) | RefSymbolic !Text++commitRefTarget :: Commit m -> RefTarget m+commitRefTarget = RefObj . commitOid++{- $merges -}+data ModificationKind = Unchanged | Modified | Added | Deleted | TypeChanged+ deriving (Eq, Ord, Enum, Show, Read)++data MergeStatus+ = NoConflict+ | BothModified+ | LeftModifiedRightDeleted+ | LeftDeletedRightModified+ | BothAdded+ | LeftModifiedRightTypeChanged+ | LeftTypeChangedRightModified+ | LeftDeletedRightTypeChanged+ | LeftTypeChangedRightDeleted+ | BothTypeChanged+ deriving (Eq, Ord, Enum, Show, Read)++mergeStatus :: ModificationKind -> ModificationKind -> MergeStatus+mergeStatus Unchanged Unchanged = NoConflict+mergeStatus Unchanged Modified = NoConflict+mergeStatus Unchanged Added = undefined+mergeStatus Unchanged Deleted = NoConflict+mergeStatus Unchanged TypeChanged = NoConflict++mergeStatus Modified Unchanged = NoConflict+mergeStatus Modified Modified = BothModified+mergeStatus Modified Added = undefined+mergeStatus Modified Deleted = LeftModifiedRightDeleted+mergeStatus Modified TypeChanged = LeftModifiedRightTypeChanged++mergeStatus Added Unchanged = undefined+mergeStatus Added Modified = undefined+mergeStatus Added Added = BothAdded+mergeStatus Added Deleted = undefined+mergeStatus Added TypeChanged = undefined++mergeStatus Deleted Unchanged = NoConflict+mergeStatus Deleted Modified = LeftDeletedRightModified+mergeStatus Deleted Added = undefined+mergeStatus Deleted Deleted = NoConflict+mergeStatus Deleted TypeChanged = LeftDeletedRightTypeChanged++mergeStatus TypeChanged Unchanged = NoConflict+mergeStatus TypeChanged Modified = LeftTypeChangedRightModified+mergeStatus TypeChanged Added = undefined+mergeStatus TypeChanged Deleted = LeftTypeChangedRightDeleted+mergeStatus TypeChanged TypeChanged = BothTypeChanged++data MergeResult m+ = MergeSuccess+ { mergeCommit :: CommitOid m+ }+ | MergeConflicted+ { mergeCommit :: CommitOid m+ , mergeHeadLeft :: CommitOid m+ , mergeHeadRight :: CommitOid m+ , mergeConflicts :: Map Text (ModificationKind, ModificationKind)+ }++copyMergeResult :: (Repository m, MonadGit m, Repository n, MonadGit n)+ => MergeResult m -> n (MergeResult n)+copyMergeResult (MergeSuccess mc) =+ MergeSuccess <$> (Tagged <$> parseOid (renderObjOid mc))+copyMergeResult (MergeConflicted hl hr mc cs) =+ MergeConflicted <$> (Tagged <$> parseOid (renderObjOid hl))+ <*> (Tagged <$> parseOid (renderObjOid hr))+ <*> (Tagged <$> parseOid (renderObjOid mc))+ <*> pure cs++instance Repository m => Show (MergeResult m) where+ show (MergeSuccess mc) = "MergeSuccess (" ++ show mc ++ ")"+ show (MergeConflicted mc hl hr cs) =+ "MergeResult"+ ++ "\n { mergeCommit = " ++ show mc+ ++ "\n , mergeHeadLeft = " ++ show hl+ ++ "\n , mergeHeadRight = " ++ show hr+ ++ "\n , mergeConflicts = " ++ show cs+ ++ "\n }"++{- $exceptions -}+-- | There is a separate 'GitException' for each possible failure when+-- interacting with the Git repository.+data GitException = BackendError Text+ | GitError Text+ | RepositoryNotExist+ | RepositoryInvalid+ | RepositoryCannotAccess Text+ | BlobCreateFailed+ | BlobEmptyCreateFailed+ | BlobEncodingUnknown Text+ | BlobLookupFailed+ | PushNotFastForward Text+ | TranslationException Text+ | TreeCreateFailed Text+ | TreeBuilderCreateFailed+ | TreeBuilderInsertFailed Text+ | TreeBuilderRemoveFailed Text+ | TreeBuilderWriteFailed Text+ | TreeLookupFailed+ | TreeCannotTraverseBlob+ | TreeCannotTraverseCommit+ | TreeEntryLookupFailed Text+ | TreeUpdateFailed+ | TreeWalkFailed+ | TreeEmptyCreateFailed+ | CommitCreateFailed+ | CommitLookupFailed Text+ | ReferenceCreateFailed+ | ReferenceDeleteFailed Text+ | RefCannotCreateFromPartialOid+ | ReferenceListingFailed+ | ReferenceLookupFailed Text+ | ObjectLookupFailed Text Int+ | ObjectRefRequiresFullOid+ | OidCopyFailed+ | OidParseFailed Text+ | QuotaHardLimitExceeded Int Int+ deriving (Eq, Show, Typeable)++-- jww (2013-02-11): Create a BackendException data constructor of forall+-- e. Exception e => BackendException e, so that each can throw a derived+-- exception.+instance Exc.Exception GitException
gitlib.cabal view
@@ -1,5 +1,5 @@ Name: gitlib-Version: 1.4.0+Version: 2.0.0.0 Synopsis: API library for working with Git repositories License-file: LICENSE License: MIT@@ -23,17 +23,17 @@ type: git location: git://github.com/fpco/gitlib.git -Test-suite doctests- Default-language: Haskell98- Type: exitcode-stdio-1.0- Main-is: Doctest.hs- Hs-source-dirs: test- Build-depends: - base- , directory >= 1.0- , doctest >= 0.8- , doctest-prop >= 0.1- , filepath >= 1.3+-- Test-suite doctests+-- Default-language: Haskell98+-- Type: exitcode-stdio-1.0+-- Main-is: Doctest.hs+-- Hs-source-dirs: test+-- Build-depends: +-- base+-- , directory >= 1.0+-- , doctest >= 0.8+-- , doctest-prop >= 0.1+-- , filepath >= 1.3 Library default-language: Haskell98@@ -58,4 +58,22 @@ , unordered-containers >= 0.2.3.0 exposed-modules: Git+ Git.Types+ Git.Blob+ Git.Tree+ Git.Tree.Builder+ Git.Tree.Builder.Pure+ Git.Commit+ Git.Commit.Push+ Git.Object+ Git.Reference+ Git.Repository Git.Tutorial+ default-extensions: + ConstraintKinds+ DeriveDataTypeable+ FlexibleContexts+ OverloadedStrings+ RankNTypes+ TypeFamilies+ ViewPatterns
− test/Doctest.hs
@@ -1,30 +0,0 @@-module Main where--import Test.DocTest-import System.Directory-import System.FilePath-import Control.Applicative-import Control.Monad-import Data.List--main :: IO ()-main = getSources >>= \sources -> doctest $- "-isrc"- : "-idist/build/autogen"- : "-optP-include"- : "-optPdist/build/autogen/cabal_macros.h"- : sources--getSources :: IO [FilePath]-getSources =- filter (\n -> ".hs" `isSuffixOf` n && n /= "./Setup.hs") <$> go "."- where- go dir = do- (dirs, files) <- getFilesAndDirectories dir- (files ++) . concat <$> mapM go (filter (not . (== "./test")) dirs)--getFilesAndDirectories :: FilePath -> IO ([FilePath], [FilePath])-getFilesAndDirectories dir = do- c <- map (dir </>) . filter (`notElem` ["..", "."])- <$> getDirectoryContents dir- (,) <$> filterM doesDirectoryExist c <*> filterM doesFileExist c