gitlib-libgit2 1.0.2 → 1.1.0
raw patch · 3 files changed
+276/−255 lines, 3 filesdep ~gitlibdep ~gitlib-libgit2dep ~gitlib-testPVP ok
version bump matches the API change (PVP)
Dependency ranges changed: gitlib, gitlib-libgit2, gitlib-test, gitlib-utils
API changes (from Hackage documentation)
- Git.Libgit2: instance Eq (Oid (LgRepository m))
- Git.Libgit2: instance Ord (Oid (LgRepository m))
- Git.Libgit2: instance Show (Oid (LgRepository m))
- Git.Libgit2.Types: type Oid m = Oid (LgRepository m)
+ Git.Libgit2: OidPtr :: ForeignPtr C'git_oid -> OidPtr
+ Git.Libgit2: data OidPtr
+ Git.Libgit2: getOid :: OidPtr -> ForeignPtr C'git_oid
+ Git.Libgit2: instance Eq OidPtr
+ Git.Libgit2: instance IsOid OidPtr
+ Git.Libgit2: instance Ord OidPtr
+ Git.Libgit2: instance Show OidPtr
+ Git.Libgit2: mkOid :: ForeignPtr C'git_oid -> OidPtr
Files
- Git/Libgit2.hs +270/−247
- Git/Libgit2/Types.hs +0/−2
- gitlib-libgit2.cabal +6/−6
Git/Libgit2.hs view
@@ -5,6 +5,7 @@ {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE UndecidableInstances #-}+{-# LANGUAGE ViewPatterns #-} {-# OPTIONS_GHC -fno-warn-name-shadowing -fno-warn-unused-binds@@ -20,7 +21,9 @@ , Commit() , CommitOid() , CommitRef()- , Git.Oid(..)+ , Git.Oid+ , OidPtr(..)+ , mkOid , Reference() , Repository(..) , Tree()@@ -96,68 +99,22 @@ debug :: MonadIO m => String -> m () --debug = liftIO . putStrLn debug = const (return ())--instance Git.MonadGit m => Git.Repository (LgRepository m) where- data Oid (LgRepository m) = Oid- { getOid :: ForeignPtr C'git_oid- }- data TreeData (LgRepository m) = TreeData- { lgPendingUpdates :: IORef (HashMap Text (Tree m))- , lgTreeContents :: ForeignPtr C'git_treebuilder- }-- data Options (LgRepository m) = Options-- facts = return Git.RepositoryFacts- { Git.hasSymbolicReferences = True- }-- parseOid = lgParseOid- renderOid = lgRenderOid- lookupRef = lgLookupRef- createRef = lgUpdateRef- updateRef = lgUpdateRef- deleteRef = lgDeleteRef- resolveRef = lgResolveRef- allRefNames = lgAllRefNames- lookupCommit = lgLookupCommit 40- lookupTree = lgLookupTree 40- lookupBlob = lgLookupBlob- lookupTag = undefined- lookupObject = lgLookupObject- existsObject = lgExistsObject- pushCommit = \name _ rrefname -> Git.genericPushCommit name rrefname- traverseCommits = lgTraverseCommits- missingObjects = lgMissingObjects- traverseObjects = error "Not defined: LgRepository.traverseObjects"- newTree = lgNewTree- hashContents = lgHashContents- createBlob = lgWrap . lgCreateBlob- createTag = undefined-- createCommit p t a c l r = lgWrap $ lgCreateCommit p t a c l r-- deleteRepository = lgGet >>= liftIO . removeTree . repoPath++type Oid = OidPtr - buildPackFile = lgBuildPackFile- buildPackIndex = lgBuildPackIndexWrapper- writePackFile = lgWrap . lgWritePackFile+data OidPtr = OidPtr { getOid :: ForeignPtr C'git_oid } - remoteFetch = lgRemoteFetch+instance Git.IsOid OidPtr where+ renderOid = lgRenderOid -lgWrap :: (MonadIO m, MonadBaseControl IO m)- => LgRepository m a -> LgRepository m a-lgWrap f = f `Exc.catch` \e -> do- etrap <- lgExcTrap- mexc <- liftIO $ readIORef etrap- liftIO $ writeIORef etrap Nothing- maybe (throw (e :: SomeException)) throw mexc+mkOid :: ForeignPtr C'git_oid -> OidPtr+mkOid = OidPtr -lgParseOid :: Git.MonadGit m => Text -> LgRepository m (Oid m)+lgParseOid :: Git.MonadGit m => Text -> LgRepository m Oid lgParseOid str | len > 40 = failure (Git.OidParseFailed str) | otherwise = do- oid <- liftIO mallocForeignPtr+ oid <- liftIO $ mallocForeignPtr r <- liftIO $ withCString (T.unpack str) $ \cstr -> withForeignPtr oid $ \ptr -> if len == 40@@ -165,18 +122,18 @@ else c'git_oid_fromstrn ptr cstr (fromIntegral len) if r < 0 then failure (Git.OidParseFailed str)- else return (Oid oid)+ else return (mkOid oid) where len = T.length str lgRenderOid :: Git.Oid (LgRepository m) -> Text lgRenderOid = T.pack . show -instance Show (Git.Oid (LgRepository m)) where- show (Oid coid) = SU.unsafePerformIO $ withForeignPtr coid oidToStr+instance Show OidPtr where+ show (getOid -> coid) = SU.unsafePerformIO $ withForeignPtr coid oidToStr -instance Ord (Git.Oid (LgRepository m)) where- Oid coid1 `compare` Oid coid2 =+instance Ord OidPtr where+ (getOid -> coid1) `compare` (getOid -> coid2) = SU.unsafePerformIO $ withForeignPtr coid1 $ \coid1Ptr -> withForeignPtr coid2 $ \coid2Ptr -> do@@ -187,9 +144,68 @@ then GT else EQ -instance Eq (Git.Oid (LgRepository m)) where+instance Eq OidPtr where oid1 == oid2 = oid1 `compare` oid2 == EQ++data TreeBuilder m = TreeBuilder+ { lgPendingUpdates :: IORef (HashMap Text (Tree m))+ , lgTreeContents :: ForeignPtr C'git_treebuilder+ } +instance Git.MonadGit m => Git.Repository (LgRepository m) where+ type Oid (LgRepository m) = OidPtr+ type Tree (LgRepository m) = TreeBuilder m++ data Options (LgRepository m) = Options++ facts = return Git.RepositoryFacts+ { Git.hasSymbolicReferences = True+ }++ parseOid = lgParseOid+ lookupRef = lgLookupRef+ createRef = lgUpdateRef+ updateRef = lgUpdateRef+ deleteRef = lgDeleteRef+ resolveRef = lgResolveRef+ allRefNames = lgAllRefNames+ lookupCommit = lgLookupCommit 40+ lookupTree = lgLookupTree 40+ lookupBlob = lgLookupBlob+ lookupTag = undefined+ lookupObject = lgLookupObject+ existsObject = lgExistsObject+ pushCommit = \name _ rrefname -> Git.genericPushCommit name rrefname+ traverseCommits = lgTraverseCommits+ missingObjects = lgMissingObjects+ traverseObjects = error "Not defined: LgRepository.traverseObjects"+ newTree = lgNewTree+ cloneTree = lgCloneTree+ traverseEntries = lgTraverseEntries+ unsafeUpdateTree = lgModifyTree+ writeTree = lgWriteTree+ hashContents = lgHashContents+ createBlob = lgWrap . lgCreateBlob+ createTag = undefined++ createCommit p t a c l r = lgWrap $ lgCreateCommit p t a c l r++ deleteRepository = lgGet >>= liftIO . removeTree . repoPath++ buildPackFile = lgBuildPackFile+ buildPackIndex = lgBuildPackIndexWrapper+ writePackFile = lgWrap . lgWritePackFile++ remoteFetch = lgRemoteFetch++lgWrap :: (MonadIO m, MonadBaseControl IO m)+ => LgRepository m a -> LgRepository m a+lgWrap f = f `Exc.catch` \e -> do+ etrap <- lgExcTrap+ mexc <- liftIO $ readIORef etrap+ liftIO $ writeIORef etrap Nothing+ maybe (throw (e :: SomeException)) throw mexc+ lgHashContents :: Git.MonadGit m => Git.BlobContents (LgRepository m) -> LgRepository m (BlobOid m) lgHashContents b = do@@ -201,7 +217,7 @@ c'git_odb_hash oidPtr (castPtr cstr) (fromIntegral len) c'GIT_OBJ_BLOB) when (r < 0) $ failure Git.BlobCreateFailed- return (Tagged (Oid ptr))+ return (Tagged (mkOid ptr)) -- | Create a new blob in the 'Repository', with 'ByteString' as its contents. --@@ -216,7 +232,7 @@ r <- Git.blobContentsToByteString b >>= \bs -> liftIO $ createBlobFromByteString repo ptr bs when (r < 0) $ failure Git.BlobCreateFailed- return (Tagged (Oid ptr))+ return (Tagged (mkOid ptr)) where createBlobFromByteString repo coid bs =@@ -246,43 +262,40 @@ type TreeEntry m = Git.TreeEntry (LgRepository m) lgTraverseEntries :: Git.MonadGit m- => Tree m- -> (FilePath -> TreeEntry m -> LgRepository m a)+ =>(FilePath -> TreeEntry m -> LgRepository m a)+ -> Tree m -> LgRepository m [a]-lgTraverseEntries initialTree f = go "" initialTree- where- go fp tree = do- entries <- liftIO $ withForeignPtr- (lgTreeContents (Git.getTreeData tree)) $ \tb -> do- ior <- newIORef []- bracket- (mk'git_treebuilder_filter_cb (callback fp ior))- freeHaskellFunPtr- (flip (c'git_treebuilder_filter tb) nullPtr)- readIORef ior- concat <$> mapM (uncurry handler) entries+lgTraverseEntries f initialTree = go "" initialTree+ where+ go fp tree = do+ entries <- liftIO $ withForeignPtr (lgTreeContents tree) $ \tb -> do+ ior <- newIORef []+ bracket+ (mk'git_treebuilder_filter_cb (callback fp ior))+ freeHaskellFunPtr+ (flip (c'git_treebuilder_filter tb) nullPtr)+ readIORef ior+ concat <$> mapM (uncurry handler) entries - handler path entry@(Git.TreeEntry tref) = do- x <- f path entry- xs <- Git.resolveTreeRef tref >>= go path- return (x:xs)- handler path entry = liftM2 (:) (f path entry) (return [])+ handler path entry@(Git.TreeEntry tref) = do+ x <- f path entry+ xs <- Git.resolveTreeRef tref >>= go path+ return (x:xs)+ handler path entry = liftM2 (:) (f path entry) (return []) - callback fp ior te _ = do- cname <- c'git_tree_entry_name te- name <- (fp </>) . F.decodeString <$> peekCString cname- entry <- entryToTreeEntry te- modifyIORef ior $- seq name $ seq entry (\xs -> (name,entry):xs)- return 0+ callback fp ior te _ = do+ cname <- c'git_tree_entry_name te+ name <- (fp </>) . F.decodeString <$> peekCString cname+ entry <- entryToTreeEntry te+ modifyIORef ior $+ seq name $ seq entry (\xs -> (name,entry):xs)+ return 0 lgMakeTree :: Git.MonadGit m => IORef (HashMap Text (Tree m)) -> ForeignPtr C'git_treebuilder- -> Tree m-lgMakeTree updates contents =- Git.mkTree lgModifyTree lgWriteTree lgTraverseEntries $- TreeData updates contents+ -> LgRepository m (Tree m)+lgMakeTree contents builder = return $ TreeBuilder contents builder -- | Create a new, empty tree. --@@ -300,10 +313,41 @@ if r < 0 then failure (Git.TreeCreateFailed "Failed to create new tree builder")- else lgMakeTree <$> liftIO (newIORef HashMap.empty)- <*> pure fptr+ else do+ contents <- liftIO (newIORef HashMap.empty)+ lgMakeTree contents fptr -lgLookupTree :: Git.MonadGit m => Int -> Tagged (Tree m) (Oid m)+lgCloneTree :: Git.MonadGit m => Tree m -> LgRepository m (Tree m)+lgCloneTree (TreeBuilder pending contents) =+ TreeBuilder <$> liftIO (newIORef =<< readIORef pending)+ <*> liftIO (copyBuilder contents)+ where+ copyBuilder fptr = withForeignPtr fptr $ \builder -> alloca $ \pptr -> do+ r <- c'git_treebuilder_create pptr nullPtr+ when (r < 0) $+ failure (Git.BackendError "Could not create new treebuilder")+ builder' <- peek pptr+ bracket+ (mk'git_treebuilder_filter_cb (callback builder'))+ freeHaskellFunPtr+ (flip (c'git_treebuilder_filter builder) nullPtr)+ FC.newForeignPtr builder'(c'git_treebuilder_free builder')++ callback builder te _ = do+ cname <- c'git_tree_entry_name te+ coid <- c'git_tree_entry_id te+ fmode <- c'git_tree_entry_filemode te+ r <- c'git_treebuilder_insert+ nullPtr+ builder+ cname+ coid+ fmode+ when (r < 0) $+ failure (Git.BackendError "Could not insert entry in treebuilder")+ return 0++lgLookupTree :: Git.MonadGit m => Int -> Tagged (Tree m) Oid -> LgRepository m (Tree m) lgLookupTree len oid = do -- jww (2013-01-28): Verify the oid here@@ -323,7 +367,7 @@ else do upds <- liftIO $ newIORef HashMap.empty return (upds,fptr)- return $ lgMakeTree upds fptr+ lgMakeTree upds fptr entryToTreeEntry :: Git.MonadGit m => Ptr C'git_tree_entry -> IO (TreeEntry m) entryToTreeEntry entry = do@@ -333,49 +377,18 @@ case () of () | typ == c'GIT_OBJ_BLOB -> do mode <- c'git_tree_entry_filemode entry- return $ Git.BlobEntry (Tagged (Oid oid)) $+ return $ Git.BlobEntry (Tagged (mkOid oid)) $ case mode of 0o100644 -> Git.PlainBlob 0o100755 -> Git.ExecutableBlob 0o120000 -> Git.SymlinkBlob _ -> Git.UnknownBlob | typ == c'GIT_OBJ_TREE ->- return $ Git.TreeEntry (Git.ByOid (Tagged (Oid oid)))+ return $ Git.TreeEntry (Git.ByOid (Tagged (mkOid oid))) | typ == c'GIT_OBJ_COMMIT ->- return $ Git.CommitEntry (Tagged (Oid oid))+ return $ Git.CommitEntry (Tagged (mkOid oid)) | otherwise -> error "Unexpected" -doLookupTreeEntry :: Git.MonadGit m- => Tree m- -> [Text]- -> LgRepository m (Maybe (TreeEntry m))-doLookupTreeEntry t [] = return (Just (Git.treeEntry t))-doLookupTreeEntry t (name:names) = do- -- Lookup the current name in this tree. If it doesn't exist, and there are- -- more names in the path and 'createIfNotExist' is True, create a new Tree- -- and descend into it. Otherwise, if it exists we'll have @Just (TreeEntry- -- {})@, and if not we'll have Nothing.- upds <- liftIO $ readIORef (lgPendingUpdates (Git.getTreeData t))- y <- case HashMap.lookup name upds of- Just m -> return . Just . Git.TreeEntry . Git.Known $ m- Nothing ->- liftIO $ withForeignPtr- (lgTreeContents (Git.getTreeData t)) $ \builder -> do- entry <- withCString (T.unpack name)- (c'git_treebuilder_get builder)- if entry == nullPtr- then return Nothing- else Just <$> entryToTreeEntry entry- if null names- then return y- else case y of- Just (Git.BlobEntry {}) -> failure Git.TreeCannotTraverseBlob- Just (Git.CommitEntry {}) -> failure Git.TreeCannotTraverseCommit- Just (Git.TreeEntry t') -> do- t'' <- Git.resolveTreeRef t'- doLookupTreeEntry t'' names- _ -> return Nothing- -- | Write out a tree to its repository. If it has already been written, -- nothing will happen. lgWriteTree :: Git.MonadGit m => Tree m -> LgRepository m (TreeOid m)@@ -384,16 +397,53 @@ emptyTreeOid <- Git.parseOid "4b825dc642cb6eb9a060e54bf8d69288fbee4904" doWriteTree t >>= return . Tagged . fromMaybe emptyTreeOid+ where+ doWriteTree tr = do+ repo <- lgGet+ let contents = lgTreeContents tr + upds <- liftIO $ readIORef (lgPendingUpdates tr)+ forM_ (HashMap.toList upds) $ \(k,v) -> do+ oid <- doWriteTree v+ case oid of+ Nothing -> dropEntry contents (T.unpack k)+ Just oid' -> insertEntry contents (T.unpack k) oid' 0o040000+ liftIO $ writeIORef (lgPendingUpdates tr) HashMap.empty++ cnt <- liftIO $ withForeignPtr contents c'git_treebuilder_entrycount+ if cnt == 0+ then return Nothing+ else go contents (repoObj repo)++ go :: Git.MonadGit m+ => ForeignPtr C'git_treebuilder+ -> ForeignPtr C'git_repository+ -> LgRepository m (Maybe Oid)+ go fptr repo = do+ (r3,coid) <- liftIO $ do+ coid <- mallocForeignPtr+ withForeignPtr coid $ \coid' ->+ withForeignPtr fptr $ \builder ->+ withForeignPtr repo $ \repoPtr -> do+ r3 <- c'git_treebuilder_write coid' repoPtr builder+ return (r3,coid)+ when (r3 < 0) $ do+ errPtr <- liftIO $ c'giterr_last+ err <- liftIO $ peek errPtr+ errStr <- liftIO $ peekCString (c'git_error'message err)+ failure (Git.TreeBuilderWriteFailed $ T.pack $+ "c'git_treebuilder_write failed with " ++ show r3+ ++ ": " ++ errStr)+ return (Just (mkOid coid))+ lgTreeEntryCount :: Git.MonadGit m => Tree m -> LgRepository m Int lgTreeEntryCount t = do- let tdata = Git.getTreeData t- contents = lgTreeContents tdata+ let contents = lgTreeContents t fromIntegral <$> liftIO (withForeignPtr contents c'git_treebuilder_entrycount) insertEntry :: Git.MonadGit m- => ForeignPtr C'git_treebuilder -> String -> Oid m -> CUInt+ => ForeignPtr C'git_treebuilder -> String -> Oid -> CUInt -> LgRepository m () insertEntry builder key oid attrs = do r2 <- liftIO $ withForeignPtr (getOid oid) $ \coid ->@@ -410,105 +460,61 @@ c'git_treebuilder_remove ptr name when (r2 < 0) $ failure (Git.TreeBuilderRemoveFailed (T.pack key)) -doWriteTree :: Git.MonadGit m => Tree m -> LgRepository m (Maybe (Oid m))-doWriteTree t = do- repo <- lgGet- let tdata = Git.getTreeData t- contents = lgTreeContents tdata-- upds <- liftIO $ readIORef (lgPendingUpdates tdata)- forM_ (HashMap.toList upds) $ \(k,v) -> do- oid <- doWriteTree v- case oid of- Nothing -> dropEntry contents (T.unpack k)- Just oid' -> insertEntry contents (T.unpack k) oid' 0o040000- liftIO $ writeIORef (lgPendingUpdates tdata) HashMap.empty-- cnt <- liftIO $ withForeignPtr contents c'git_treebuilder_entrycount- if cnt == 0- then return Nothing- else go contents (repoObj repo)+lgModifyTree :: Git.MonadGit m+ => Tree m -> FilePath -> Bool+ -> (Maybe (TreeEntry m) -> Git.ModifyTreeResult (LgRepository m))+ -> LgRepository m (Tree m, Maybe (TreeEntry m))+lgModifyTree t path createIfNotExist f =+ fmap Git.fromModifyTreeResult+ <$> doModifyTree t (splitPath path) createIfNotExist where- go :: Git.MonadGit m- => ForeignPtr C'git_treebuilder- -> ForeignPtr C'git_repository- -> LgRepository m (Maybe (Oid m))- go fptr repo = do- (r3,coid) <- liftIO $ do- coid <- mallocForeignPtr- withForeignPtr coid $ \coid' ->- withForeignPtr fptr $ \builder ->- withForeignPtr repo $ \repoPtr -> do- r3 <- c'git_treebuilder_write coid' repoPtr builder- return (r3,coid)- when (r3 < 0) $ do- errPtr <- liftIO $ c'giterr_last- err <- liftIO $ peek errPtr- errStr <- liftIO $ peekCString (c'git_error'message err)- failure (Git.TreeBuilderWriteFailed $ T.pack $- "c'git_treebuilder_write failed with " ++ show r3- ++ ": " ++ errStr)- return (Just (Oid coid))--doModifyTree :: Git.MonadGit m- => Tree m- -> [Text]- -> Bool- -> (Maybe (TreeEntry m)- -> LgRepository m (Git.ModifyTreeResult (LgRepository m)))- -> LgRepository m (Git.ModifyTreeResult (LgRepository m))-doModifyTree t [] _ _ =- return . Git.TreeEntryPersistent . Git.TreeEntry . Git.Known $ t-doModifyTree t (name:names) createIfNotExist f = do -- Lookup the current name in this tree. If it doesn't exist, and there -- are more names in the path and 'createIfNotExist' is True, create a new -- Tree and descend into it. Otherwise, if it exists we'll have @Just -- (TreeEntry {})@, and if not we'll have Nothing.- y' <- doLookupTreeEntry t [name]- y <- if isNothing y' && createIfNotExist && not (null names)- then Just . Git.TreeEntry . Git.Known <$> Git.newTree- else return y'+ doModifyTree tr [] _ =+ return (tr, Git.TreeEntryPersistent . Git.TreeEntry . Git.Known $ tr)+ doModifyTree tr (name:names) createIfNotExist = do+ y' <- doLookupTreeEntry tr [name]+ y <- if isNothing y' && createIfNotExist && not (null names)+ then Just . Git.TreeEntry . Git.Known <$> Git.newTree+ else return y'+ go tr name names y - if null names- then do- -- If there are no further names in the path, call the transformer- -- function, f. It receives a @Maybe TreeEntry@ to indicate if there- -- was a previous entry at this path. It should return a 'Left' value- -- to propagate out a user-defined error, or a @Maybe TreeEntry@ to- -- indicate whether the entry at this path should be deleted or- -- replaced with something new.- --- -- NOTE: There is no provision for leaving the entry unchanged! It is- -- assumed to always be changed, as we have no reliable method of- -- testing object equality that is not O(n).- ze <- f y- returnTree (Git.getTreeData t) (T.unpack name) ze+ -- If there are no further names in the path, call the transformer+ -- function, f. It receives a @Maybe TreeEntry@ to indicate if there was+ -- a previous entry at this path. It should return a 'Left' value to+ -- propagate out a user-defined error, or a @Maybe TreeEntry@ to indicate+ -- whether the entry at this path should be deleted or replaced with+ -- something new.+ --+ -- NOTE: There is no provision for leaving the entry unchanged! It is+ -- assumed to always be changed, as we have no reliable method of testing+ -- object equality that is not O(n).+ go tr name [] y = returnTree tr (T.unpack name) (f y) - else- -- If there are further names in the path, descend them now. If- -- 'createIfNotExist' was False and there is no 'Tree' under the- -- current name, or if we encountered a 'Blob' when a 'Tree' was- -- required, throw an exception to avoid colliding with user-defined- -- 'Left' values.- case y of- Nothing -> return Git.TreeEntryNotFound- Just (Git.BlobEntry {}) -> failure Git.TreeCannotTraverseBlob- Just (Git.CommitEntry {}) -> failure Git.TreeCannotTraverseCommit- Just (Git.TreeEntry st') -> do- st <- Git.resolveTreeRef st'- ze <- doModifyTree st names createIfNotExist f- case ze of- Git.TreeEntryNotFound -> return ze- Git.TreeEntryPersistent _ -> return ze- Git.TreeEntryDeleted -> postUpdate st ze- Git.TreeEntryMutated _ -> postUpdate st ze- where- postUpdate st ze = do- liftIO $ modifyIORef- (lgPendingUpdates (Git.getTreeData t))- (HashMap.insert name st)- return ze+ go tr _ _ Nothing = return (tr, Git.TreeEntryNotFound)+ go _ _ _ (Just Git.BlobEntry {}) = failure Git.TreeCannotTraverseBlob+ go _ _ _ (Just Git.CommitEntry {}) = failure Git.TreeCannotTraverseCommit + -- If there are further names in the path, descend them now. If+ -- 'createIfNotExist' was False and there is no 'Tree' under the current+ -- name, or if we encountered a 'Blob' when a 'Tree' was required, throw+ -- an exception to avoid colliding with user-defined 'Left' values.+ go tr name names (Just (Git.TreeEntry st')) = do+ st <- Git.resolveTreeRef st'+ (st'', ze) <- doModifyTree st names createIfNotExist+ case ze of+ Git.TreeEntryNotFound -> return ()+ Git.TreeEntryPersistent _ -> return ()+ Git.TreeEntryDeleted -> postUpdate tr st'' name+ Git.TreeEntryMutated _ -> postUpdate tr st'' name+ return (tr, ze)++ postUpdate tr st name =+ liftIO $ modifyIORef (lgPendingUpdates tr) $+ HashMap.insert name st+ returnTree tr n z = do let contents = lgTreeContents tr case z of@@ -518,7 +524,7 @@ Git.TreeEntryMutated z' -> do (oid,mode) <- treeEntryToOid z' insertEntry contents n oid mode- return z+ return (tr, z) treeEntryToOid (Git.BlobEntry oid kind) = return (unTagged oid,@@ -533,15 +539,31 @@ oid <- Git.treeRefOid tr return (unTagged oid, 0o040000) -lgModifyTree- :: Git.MonadGit m- => Tree m -> FilePath -> Bool- -> (Maybe (TreeEntry m)- -> LgRepository m (Git.ModifyTreeResult (LgRepository m)))- -> LgRepository m (Maybe (TreeEntry m))-lgModifyTree t path createIfNotExist f =- Git.fromModifyTreeResult <$>- doModifyTree t (splitPath path) createIfNotExist f+ -- Lookup the current name in this tree. If it doesn't exist, and there+ -- are more names in the path and 'createIfNotExist' is True, create a new+ -- Tree and descend into it. Otherwise, if it exists we'll have @Just+ -- (TreeEntry {})@, and if not we'll have Nothing.+ doLookupTreeEntry tr [] = return (Just (Git.treeEntry tr))+ doLookupTreeEntry tr (name:names) = do+ upds <- liftIO $ readIORef (lgPendingUpdates tr)+ y <- case HashMap.lookup name upds of+ Just m -> return . Just . Git.TreeEntry . Git.Known $ m+ Nothing ->+ liftIO $ withForeignPtr (lgTreeContents tr) $ \builder -> do+ entry <- withCString (T.unpack name)+ (c'git_treebuilder_get builder)+ if entry == nullPtr+ then return Nothing+ else Just <$> entryToTreeEntry entry+ if null names+ then return y+ else case y of+ Just (Git.BlobEntry {}) -> failure Git.TreeCannotTraverseBlob+ Just (Git.CommitEntry {}) -> failure Git.TreeCannotTraverseCommit+ Just (Git.TreeEntry st) -> do+ st' <- Git.resolveTreeRef st+ doLookupTreeEntry st' names+ _ -> return Nothing splitPath :: FilePath -> [Text] splitPath path = T.splitOn "/" text@@ -574,14 +596,15 @@ (replicate (fromIntegral (toInteger pn)) (c'git_commit_parent_id c)) [0..pn]- poids' <- mapM (\x -> Git.ByOid . Tagged . Oid <$> coidPtrToOid x) poids+ poids' <- mapM (\x -> Git.ByOid . Tagged . mkOid+ <$> coidPtrToOid x) poids return Git.Commit { -- Git.commitInfo = Base (Just (Tagged (Oid coid))) (Just obj) -- , Git.commitOid = oid- , Git.commitTree = Git.ByOid (Tagged (Oid toid'))+ , Git.commitTree = Git.ByOid (Tagged (mkOid toid')) , Git.commitParents = poids' , Git.commitAuthor = auth , Git.commitCommitter = comm@@ -616,15 +639,15 @@ go coid _ y = do typ <- liftIO $ c'git_object_type y case () of- () | typ == c'GIT_OBJ_BLOB -> ret Git.BlobObj (Oid coid)- | typ == c'GIT_OBJ_TREE -> ret Git.TreeObj (Oid coid)- | typ == c'GIT_OBJ_COMMIT -> ret Git.CommitObj (Oid coid)- | typ == c'GIT_OBJ_TAG -> ret Git.TagObj (Oid coid)+ () | typ == c'GIT_OBJ_BLOB -> ret Git.BlobObj (mkOid coid)+ | typ == c'GIT_OBJ_TREE -> ret Git.TreeObj (mkOid coid)+ | typ == c'GIT_OBJ_COMMIT -> ret Git.CommitObj (mkOid coid)+ | typ == c'GIT_OBJ_TAG -> ret Git.TagObj (mkOid coid) | otherwise -> failure (Git.ObjectLookupFailed str len) ret f = return . f . Git.ByOid . Tagged -lgExistsObject :: Git.MonadGit m => Oid m -> LgRepository m Bool+lgExistsObject :: Git.MonadGit m => Oid -> LgRepository m Bool lgExistsObject oid = do repo <- lgGet result <- liftIO $ withForeignPtr (repoObj repo) $ \repoPtr ->@@ -675,7 +698,7 @@ (fromIntegral ((1 :: Int) .|. (4 :: Int))) whileM ((==) <$> pure 0 <*> c'git_revwalk_next coidPtr walker)- (Git.ByOid . Tagged . Oid <$> coidPtrToOid coidPtr)+ (Git.ByOid . Tagged . mkOid <$> coidPtrToOid coidPtr) where pushOid oid = withForeignPtr oid $ \coid -> do@@ -765,7 +788,7 @@ { -- Git.commitInfo = Base (Just (Tagged (Oid coid))) Nothing -- ,- Git.commitOid = Tagged (Oid coid)+ Git.commitOid = Tagged (mkOid coid) , Git.commitTree = tree , Git.commitParents = parents , Git.commitAuthor = author@@ -801,7 +824,7 @@ typ <- c'git_reference_type ref targ <- if typ == c'GIT_REF_OID then do oidPtr <- c'git_reference_target ref- Git.RefObj . Git.ByOid . Tagged . Oid+ Git.RefObj . Git.ByOid . Tagged . mkOid <$> coidPtrToOid oidPtr else do targName <- c'git_reference_symbolic_target ref Git.RefSymbolic . T.decodeUtf8@@ -855,7 +878,7 @@ if r < 0 then return Nothing else Just <$> coidPtrToOid ptr- return (Git.ByOid . Tagged . Oid <$> oid)+ return (Git.ByOid . Tagged . mkOid <$> oid) -- int git_reference_rename(git_reference *ref, const char *new_name, -- int force)
Git/Libgit2/Types.hs view
@@ -88,8 +88,6 @@ liftBaseWith = defaultLiftBaseWith StMT restoreM = defaultRestoreM unStMT -type Oid m = Git.Oid (LgRepository m)- type BlobOid m = Git.BlobOid (LgRepository m) type TreeOid m = Git.TreeOid (LgRepository m) type CommitOid m = Git.CommitOid (LgRepository m)
gitlib-libgit2.cabal view
@@ -1,5 +1,5 @@ Name: gitlib-libgit2-Version: 1.0.2+Version: 1.1.0 Synopsis: Libgit2 backend for gitlib License-file: LICENSE License: MIT@@ -23,9 +23,9 @@ Hs-source-dirs: test Build-depends: base >=3- , gitlib- , gitlib-test- , gitlib-libgit2+ , gitlib >= 1.1.0+ , gitlib-test >= 1.1.0+ , gitlib-libgit2 >= 1.1.0 , HUnit >= 1.2.5 , hspec >= 1.4.4 , hspec-expectations >= 0.3@@ -36,8 +36,8 @@ ghc-options: -Wall build-depends: base >= 3 && < 5- , gitlib- , gitlib-utils+ , gitlib >= 1.1.0+ , gitlib-utils >= 1.1.0 , hlibgit2 >= 0.18.0.7 , attempt >= 0.4.0 , bytestring >= 0.9.2.1