Git protocol implementation in pure Haskell
Clone
HTTPS:
darcs clone https://vervis.peers.community/repos/rL9jo
SSH:
darcs clone USERNAME@vervis.peers.community:rL9jo
Tags
TODO
Put.hs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 | {- This file is part of hit-network.
-
- Written in 2016 by fr33domlover <fr33domlover@riseup.net>.
-
- ♡ Copying is an act of love. Please copy, reuse and share.
-
- The author(s) have dedicated all copyright and related and neighboring
- rights to this software to the public domain worldwide. This software is
- distributed without any warranty.
-
- You should have received a copy of the CC0 Public Domain Dedication along
- with this software. If not, see
- <http://creativecommons.org/publicdomain/zero/1.0/>.
-}
{-# LANGUAGE MultiWayIf #-}
{-# LANGUAGE OverloadedStrings #-}
-- | Helpers for putting git pack protocol elements.
module Network.Git.Put
( -- * Object ID
zeroObjId
, putObjId
-- * Capability
, serializeSharedCapability
, serializeFetchCapability
, putlenCapabilitiesFetch
-- * Pkt Line
, putFlushPkt
, putDataPkt
-- * Common Lines
, putTaggedObjId
-- * Service
, serializeService
)
where
import Control.Monad (when)
import Data.Binary.Put
import Data.Bool (bool)
import Data.ByteString (ByteString)
import Data.Foldable (traverse_)
import Data.Git.Harder (ObjId (..))
--import Data.Git.Named (RefName (..))
import Data.Git.Ref (fromHex, toHex)
--import Data.Git.Repository (branchList, tagList)
--import Data.Git.Storage (Git, getObject)
--import Data.Git.Storage.Object (Object (ObjTag))
--import Data.Git.Types (Tag (tagRef))
import Data.Monoid ((<>))
import qualified Data.ByteString as B
import Data.Binary.Put.Local
import Network.Git.Types
zeroObjId :: ObjId
zeroObjId = ObjId $ fromHex $ B.replicate 40 48 -- 40 times '0'
putObjId :: ObjId -> Put
putObjId (ObjId ref) = putByteString $ toHex ref
serializeSharedCapability :: SharedCapability -> ByteString
serializeSharedCapability cap =
case cap of
CapOfsDelta -> "ofs-delta"
CapSideBand64k -> "side-band-64k"
CapAgent agent -> "agent=" <> agent
serializeFetchCapability :: FetchCapability -> ByteString
serializeFetchCapability cap =
case cap of
CapMultiAck -> "multi_ack"
CapMultiAckDetailed -> "multi_ack_detailed"
CapNoDone -> "no-done"
CapThinPack True -> "thin-pack"
CapThinPack False -> "no-thin"
CapSideBand -> "side-band"
CapShallow -> "shallow"
CapNoProgress -> "no-progres"
CapIncludeTag -> "include-tag"
CapAllowTipSHA1InWant -> "allow-tip-sha1-in-want"
CapAllowReachableSha1InWant -> "allow-reachable-sha1-in-want"
putlenCapabilitiesFetch
:: [SharedCapability] -> [FetchCapability] -> (Put, Int)
putlenCapabilitiesFetch scaps fcaps =
let ss = map serializeSharedCapability scaps
fs = map serializeFetchCapability fcaps
slens = map B.length ss
flens = map B.length fs
foldLen = foldr $ \ x s -> x + 1 + s
len = case (slens, flens) of
([], []) -> 0
(n:ns, []) -> foldLen n ns
([], m:ms) -> foldLen m ms
(n:ns, m:ms) -> foldLen n ns + 1 + foldLen m ms
putCaps [] = return ()
putCaps (b:bs) = do
putByteString b
traverse_ (\ c -> putSpace >> putByteString c) bs
put = case (null ss, null fs) of
(True, True) -> return ()
(False, True) -> putCaps ss
(True, False) -> putCaps fs
(False, False) -> putCaps ss >> putSpace >> putCaps fs
in (put, len)
putFlushPkt :: Put
putFlushPkt = putByteString "0000" >> flush
putDataPkt :: Bool -> Int -> Put -> Put
putDataPkt addLF payloadLen payloadPut =
let len = bool id (+1) addLF $ payloadLen
in if | len == 0 -> fail "tried to put an empty pkt-line"
| len > 65520 -> fail "payload bigger than maximal pkt-len"
| otherwise -> do
putHex16 $ len + 4
payloadPut
when addLF $ putLF
putTaggedObjId :: ByteString -> ObjId -> Put
putTaggedObjId tag oid =
let len = B.length tag + 1 + 40
in putDataPkt True len $ do
putByteString tag
putSpace
putObjId oid
serializeService :: Service -> ByteString
serializeService UploadPack = "git-upload-pack"
|