ref:726fbbcf1ee0a54153160d6e485fad116e5bc8f3

Add pack protocol: pkt-line, pack writer, receive-pack, upload-pack

Phase 6 of ex_git_objectstore. Implements: - PktLine: encode/decode pkt-line format with flush/delim/sideband support - Pack.Writer: generate packfiles + .idx v2 from object lists - ReceivePack: server-side state machine for git push (ref advertisement, command parsing, pack ingestion, ref updates, status report) - UploadPack: server-side state machine for git clone/fetch (ref advertisement, want/have negotiation, pack generation with sideband) Also fixes Pack.Reader decompress_data to handle trailing data from sequential packfile parsing using binary-probed compressed length. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
SHA: 726fbbcf1ee0a54153160d6e485fad116e5bc8f3
Author: Cole Christensen <cole.christensen@macmillan.com>
Date: 2026-02-10 08:00
Parents: 3b5c899
10 files changed +1665 -37
Type
lib/ex_git_objectstore/object.ex +20 −0
@@ -119,6 +119,26 @@
defp decode_typed("tag", content), do: Tag.parse_content(content)
defp decode_typed(type, _content), do: {:error, {:unknown_type, type}}
@doc """
Encode just the content portion of a git object (no header).
"""
@spec encode_content_only(t()) :: binary()
def encode_content_only(object) do
{_type_str, content} = encode_content(object)
content
end
@doc """
Encode raw object from type atom and content binary.
Produces `"<type> <size>\\0<content>"` format.
"""
@spec encode_raw_from_type(atom(), binary()) :: binary()
def encode_raw_from_type(type, content) when is_atom(type) and is_binary(content) do
type_str = Atom.to_string(type)
header = "#{type_str} #{byte_size(content)}\0"
<<header::binary, content::binary>>
end
defp zlib_compress(data) do
z = :zlib.open()
:zlib.deflateInit(z)