gitlib-0.5.0: Data/Git/Blob.hs
{-# LANGUAGE OverloadedStrings #-}
module Data.Git.Blob
( Blob(..)
, newBlobBase
, createBlob
, getBlobContents
, writeBlob )
where
import Data.ByteString as B hiding (map)
import Data.ByteString.Unsafe
import Data.Git.Common
import Data.Git.Errors
import Data.Git.Internal
import qualified Prelude
default (Text)
data Blob = Blob { blobInfo :: Base Blob
, blobContents :: B.ByteString }
instance Show Blob where
show x = case gitId (blobInfo x) of
Pending _ -> "Blob"
Stored y -> "Blob#" ++ show y
instance Updatable Blob where
getId x = gitId (blobInfo x)
objectRepo x = gitRepo (blobInfo x)
objectPtr x = gitObj (blobInfo x)
update = writeBlob
lookupFunction = lookupBlob
newBlobBase :: Blob -> Base Blob
newBlobBase b =
newBase (gitRepo (blobInfo b)) (Pending doWriteBlob) Nothing
-- | Create a new blob in the 'Repository', with 'ByteString' as its contents.
--
-- Note that since empty blobs cannot exist in Git, no means is provided for
-- creating one; if the give string is 'empty', it is an error.
createBlob :: B.ByteString -> Repository -> Blob
createBlob text repo
| text == B.empty = error "Cannot create an empty blob"
| otherwise =
Blob { blobInfo = newBase repo (Pending doWriteBlob) Nothing
, blobContents = text }
lookupBlob :: Oid -> Repository -> IO (Maybe Blob)
lookupBlob oid repo =
lookupObject' oid repo c'git_blob_lookup c'git_blob_lookup_prefix $
\coid obj _ ->
return Blob { blobInfo = newBase repo (Stored coid) (Just obj)
, blobContents = B.empty }
getBlobContents :: Blob -> IO (Blob, B.ByteString)
getBlobContents b =
case gitId (blobInfo b) of
Pending _ -> return (b, contents)
Stored hash ->
if contents /= B.empty
then return (b, contents)
else
case gitObj (blobInfo b) of
Just blobPtr ->
withForeignPtr blobPtr $ \ptr -> do
size <- c'git_blob_rawsize (castPtr ptr)
buf <- c'git_blob_rawcontent (castPtr ptr)
bstr <- curry unsafePackCStringLen (castPtr buf)
(fromIntegral size)
return (b { blobContents = bstr }, bstr)
Nothing -> do
b' <- lookupBlob (Oid hash) repo
case b' of
Just blobPtr' -> getBlobContents blobPtr'
Nothing -> return (b, B.empty)
where repo = gitRepo (blobInfo b)
contents = blobContents b
-- | Write out a blob to its repository. If it has already been written,
-- nothing will happen.
writeBlob :: Blob -> IO Blob
writeBlob b@(Blob { blobInfo = Base { gitId = Stored _ } }) = return b
writeBlob b = do hash <- doWriteBlob b
return b { blobInfo = (blobInfo b) { gitId = Stored hash }
, blobContents = B.empty }
doWriteBlob :: Blob -> IO COid
doWriteBlob b = do
ptr <- mallocForeignPtr
r <- withForeignPtr repo (createFromBuffer ptr)
when (r < 0) $ throwIO BlobCreateFailed
return (COid ptr)
where
repo = fromMaybe (error "Repository invalid")
(repoObj (gitRepo (blobInfo b)))
createFromBuffer ptr repoPtr =
unsafeUseAsCStringLen (blobContents b) $
uncurry (\cstr len ->
withForeignPtr ptr $ \ptr' ->
c'git_blob_create_frombuffer
ptr' repoPtr (castPtr cstr) (fromIntegral len))
-- Blob.hs