By | fr33domlover |
At | 2016-04-28 |
Title | Move pack writer to hit-harder package |
Description |
Edit file src/Network/Git/Transport/HTTP/Fetch/Packfile.hs 0 → 0
- 1 {- This file is part of hit-network.
- 2 -
- 3 - Written in 2016 by fr33domlover <fr33domlover@riseup.net>.
- 4 -
- 5 - ♡ Copying is an act of love. Please copy, reuse and share.
- 6 -
- 7 - The author(s) have dedicated all copyright and related and neighboring
- 8 - rights to this software to the public domain worldwide. This software is
- 9 - distributed without any warranty.
- 10 -
- 11 - You should have received a copy of the CC0 Public Domain Dedication along
- 12 - with this software. If not, see
- 13 - <http://creativecommons.org/publicdomain/zero/1.0/>.
- 14 -}
- 15 - 16 module Network.Git.Transport.HTTP.Fetch.Packfile
- 17 (
- 18 )
- 19 where
- 20 - 21 putPackHeader :: Int -> Put
- 22 putPackHeader numOfObjects = do
- 23 putByteString "PACK" -- Signature
- 24 putWord32be 2 -- Version number
- 25 putInt32be numOfObjects -- Number of objects contained in the pack
- 26 - 27 type ObjIdSet = HashSet ObjId
- 28 - 29 -- | Take a minimal list of commits we must send, and build a set of object IDs
- 30 -- of these commits and all the trees and blobs they refer to recursively.
- 31 collectObjIds :: Git -> [(ObjId, Commit)] -> IO ObjIdSet
- 32 collectObjIds git pairs = do
- 33 let (commitIds, commits) = unzip pairs
- 34 treeIds = map (commitTreeish git) commits
- 35 resolve tid = do
- 36 mtree <- resolveTreeish git $ unObjId tid
- 37 return $ fromMaybe (error "invalid commit treeish ref") mtree
- 38 visit s oid _ _ _ = S.insert oid s
- 39 collect = traverseTree git visit
- 40 trees <- traverse resolve treeIds
- 41 let initial = S.toList commitsIds `S.union` S.toList treeIds
- 42 foldlM (flip collect) initial trees
- 43 - 44 data CompressedObject = CompressedObject
- 45 { zoType :: ObjectType
- 46 , zoSize :: Word64
- 47 , zoData :: BL.ByteString
- 48 }
- 49 - 50 objectTypeCode :: Num a => ObjectType -> a
- 51 objectTypeCode TypeCommit = 1
- 52 objectTypeCode TypeTree = 2
- 53 objectTypeCode TypeBlob = 3
- 54 objectTypeCode TypeTag = 4
- 55 objectTypeCode TypeDeltaOff = 6
- 56 objectTypeCode TypeDeltaRef = 7
- 57 - 58 -- | This is an encoder for a specific encoding of arbitrary-length numbers
- 59 -- used by Git. The purpose is to support objects of arbitrary size, not
- 60 -- limiting their size representation to 32 or 64 bits.
- 61 --
- 62 -- The encoding work as follows. The number is split into sequences of 7 bits,
- 63 -- in little endian order (i.e. least significant bits come first). For each
- 64 -- sequence, a byte is constructed. The sequence serve as the low 7 bits of it,
- 65 -- and the highest bit determines whether there is another sequence after it.
- 66 -- In other words, the last byte has that bit set to 0, and all other bytes
- 67 -- have it set to 1.
- 68 --
- 69 -- The encoding contains at least one byte. If the word value is 127 or less,
- 70 -- i.e. can be expressed in 7 bits, the encoding contains a single byte.
- 71 -- Otherwise, it's more than one byte, as needed.
- 72 putExtensibleWord :: Bits a => a -> Put
- 73 putExtensibleWord
- 74 - 75 -- | Like 'putExtensibleWord'', but lets you manually pass the first 7 bits
- 76 -- separately from the rest of the bits.
- 77 --
- 78 -- If the rest of the bits are all zeros, te encoding will contain a single
- 79 -- byte (the first 7 bits passed, and a zero high bit). Otherwise, it will
- 80 -- contain at least 2 bytes: 1 byte for the first 7 bits, and at least 1 byte
- 81 -- for the rest of the bits.
- 82 putExtensibleWord'
- 83 :: Bits a
- 84 => Word8 -- ^ The low 7 bits of the word
- 85 -> a -- ^ The rest of the bits
- 86 -> Put
- 87 putExtensibleWord' first rest =
- 88 let setHigh = (.|. 0x80)
- 89 clearHigh = (.&. 0x7f)
- 90 continues = setHigh
- 91 stops = clearHigh
- 92 if rest == zeroBits
- 93 then putWord8 $ stops first
- 94 else do
- 95 putWord8 $ continues first
- 96 let mnextF = fromIntegralSized $ rest .&. 0x7f
- 97 msg =
- 98 "toIntegralSized failed to convert small Bits a (0-127) \
- 99 \to Word8"
- 100 nextF = fromMaybe (error msg) mnextF
- 101 nextR = unsafeShiftR rest 7
- 102 putExtensibleWord' nextF nextR
- 103 - 104 putObjectHeader :: ObjectType -> Word64 -> Put
- 105 putObjectHeader otype size =
- 106 let typeBits = objectTypeCode otype
- 107 msizeLowBits = toIntegralSized $ size .&. 0x0f
- 108 sizeLowBits = case msizeLowBits of
- 109 Nothing ->
- 110 error
- 111 "toIntegralSized failed to convert small (0-15) Word64 to \
- 112 \Word8 in putObjectHeader"
- 113 Just n -> n
- 114 first7bits = unsafeShiftL typeBits 4 .|. sizeLowBits
- 115 in putExtensibleWord' first7bits (unsafeShiftR size 4)
- 116 - 117 putCompressedObject :: CompressedObject -> Put
- 118 putCompressedObject zo = do
- 119 putObjectHeader (zoType zo) (zoSize zo)
- 120 putLazyByteString $ zoData zo
- 121 - 122 compressObject :: ObjectInfo -> CompressedObject
- 123 compressObect (ObjectInfo (t, s, _mp) odata _ochains) = CompressedObject
- 124 { zoType = t
- 125 , zoSize = s
- 126 , zoData = compress odata
- 127 }
- 128 - 129 putObject :: ObjectInfo -> Put
- 130 putObject = putCompressedObject . compressObject
- 131 - 132 mkPutObject :: Git -> ObjId -> IO Put
- 133 mkPutObject git oid = do
- 134 minfo <- getObjectRaw git (unObjId oid) True
- 135 case minfo of
- 136 Nothing -> error "failed to load raw object from oid"
- 137 Just info -> return $ putObject info
- 138 - 139 writeHashed :: Put -> HashT SHA1 IO Put
- 140 writeHashed put = do
- 141 let lbs = runPut put
- 142 updateHashMulti $ toChunks lbs
- 143 return $ putLazyByteString lbs
- 144 - 145 writePack :: Git -> ObjIdSet -> IO Put
- 146 writePack git oidset = do
- 147 (put, digest) <- runHashT $ do
- 148 header <- writeHashed $ putPackHeader $ S.size oidset
- 149 let writeObj oid = liftIO (mkPutObject git oid) >>= writeHashed
- 150 foldlM (\ put oid -> (put >>) <$> writeObj oid) header oidset
- 151 return $ put >> putByteString (convert digest)
… … … … Remove file src/Network/Git/Transport/HTTP/Fetch/Packfile.hs 0