aboutsummaryrefslogtreecommitdiff
path: root/protocol/v0v1
diff options
context:
space:
mode:
authorGravatar Runxi Yu2026-03-25 16:22:03 +0000
committerGravatar Runxi Yu2026-03-25 16:22:03 +0000
commit311edcd50f3a84f4b860bde3cb887451d74eaa11 (patch)
treebe7aa5e9a51e636358f33b1c90637b5024b70dc3 /protocol/v0v1
parentREADME: Split off contrib, benchmarks, remove history for now I guess, etc. (diff)
signatureNo signature
network/protocol: Rename from protocol v0.1.110
Diffstat (limited to 'protocol/v0v1')
-rw-r--r--protocol/v0v1/doc.go2
-rw-r--r--protocol/v0v1/server/advertise.go55
-rw-r--r--protocol/v0v1/server/advertise_test.go101
-rw-r--r--protocol/v0v1/server/advertised_ref.go22
-rw-r--r--protocol/v0v1/server/doc.go2
-rw-r--r--protocol/v0v1/server/errors.go18
-rw-r--r--protocol/v0v1/server/frame.go20
-rw-r--r--protocol/v0v1/server/helpers.go29
-rw-r--r--protocol/v0v1/server/helpers_test.go28
-rw-r--r--protocol/v0v1/server/receivepack/capabilities.go192
-rw-r--r--protocol/v0v1/server/receivepack/doc.go2
-rw-r--r--protocol/v0v1/server/receivepack/errors.go11
-rw-r--r--protocol/v0v1/server/receivepack/helpers_test.go28
-rw-r--r--protocol/v0v1/server/receivepack/parse_test.go255
-rw-r--r--protocol/v0v1/server/receivepack/report_status.go185
-rw-r--r--protocol/v0v1/server/receivepack/report_status_test.go293
-rw-r--r--protocol/v0v1/server/receivepack/session.go295
-rw-r--r--protocol/v0v1/server/receivepack/types.go45
-rw-r--r--protocol/v0v1/server/session.go131
-rw-r--r--protocol/v0v1/server/version.go12
20 files changed, 0 insertions, 1726 deletions
diff --git a/protocol/v0v1/doc.go b/protocol/v0v1/doc.go
deleted file mode 100644
index 2c96ea23..00000000
--- a/protocol/v0v1/doc.go
+++ /dev/null
@@ -1,2 +0,0 @@
-// Package v0v1 provides common constants and routines for the V0 and V1 protocols.
-package v0v1
diff --git a/protocol/v0v1/server/advertise.go b/protocol/v0v1/server/advertise.go
deleted file mode 100644
index be1b1f02..00000000
--- a/protocol/v0v1/server/advertise.go
+++ /dev/null
@@ -1,55 +0,0 @@
-package server
-
-import (
- "fmt"
- "strings"
-
- objectid "codeberg.org/lindenii/furgit/object/id"
-)
-
-// AdvertiseRefs writes one server ref advertisement.
-func (session *Session) AdvertiseRefs(ad Advertisement, capabilityTokens []string) error {
- if session.opts.Version == Version1 {
- err := session.enc.WriteData([]byte("version 1\n"))
- if err != nil {
- return err
- }
- }
-
- capList := strings.Join(capabilityTokens, " ")
-
- refs := sortAdvertisedRefs(ad.Refs)
- if len(refs) == 0 {
- line := fmt.Sprintf("%s capabilities^{}\x00%s\n", objectid.Zero(session.opts.Algorithm), capList)
-
- err := session.enc.WriteData([]byte(line))
- if err != nil {
- return err
- }
-
- return session.WriteFlush()
- }
-
- for i, entry := range refs {
- line := fmt.Sprintf("%s %s", entry.ID, entry.Name)
- if i == 0 {
- line += "\x00" + capList
- }
-
- err := session.enc.WriteData([]byte(line + "\n"))
- if err != nil {
- return err
- }
-
- if entry.Peeled != nil {
- peeled := fmt.Sprintf("%s %s^{}\n", *entry.Peeled, entry.Name)
-
- err = session.enc.WriteData([]byte(peeled))
- if err != nil {
- return err
- }
- }
- }
-
- return session.WriteFlush()
-}
diff --git a/protocol/v0v1/server/advertise_test.go b/protocol/v0v1/server/advertise_test.go
deleted file mode 100644
index 287bb61d..00000000
--- a/protocol/v0v1/server/advertise_test.go
+++ /dev/null
@@ -1,101 +0,0 @@
-package server_test
-
-import (
- "strings"
- "testing"
-
- "codeberg.org/lindenii/furgit/internal/testgit"
- objectid "codeberg.org/lindenii/furgit/object/id"
- server "codeberg.org/lindenii/furgit/protocol/v0v1/server"
-)
-
-func TestAdvertiseRefsWritesVersionOneHeadCapsAndPeeledTag(t *testing.T) {
- t.Parallel()
-
- //nolint:thelper
- testgit.ForEachAlgorithm(t, func(t *testing.T, algo objectid.Algorithm) {
- t.Parallel()
-
- headID := mustHexID(t, algo, "1")
- tagID := mustHexID(t, algo, "2")
- peeledID := mustHexID(t, algo, "3")
- mainID := mustHexID(t, algo, "4")
-
- var out bufferWriteFlusher
-
- session := server.NewSession(
- strings.NewReader(""),
- &out,
- server.Options{
- Version: server.Version1,
- Algorithm: algo,
- },
- )
-
- err := session.AdvertiseRefs(server.Advertisement{
- Refs: []server.AdvertisedRef{
- {Name: "refs/tags/v1", ID: tagID, Peeled: &peeledID},
- {Name: "HEAD", ID: headID},
- {Name: "refs/heads/main", ID: mainID},
- },
- }, []string{
- "report-status",
- "delete-refs",
- "object-format=" + algo.String(),
- "agent=furgit-test/1",
- })
- if err != nil {
- t.Fatalf("AdvertiseRefs: %v", err)
- }
-
- got := out.String()
- wantParts := []string{
- "000eversion 1\n",
- headID.String() + " HEAD\x00report-status delete-refs object-format=" + algo.String() + " agent=furgit-test/1\n",
- mainID.String() + " refs/heads/main\n",
- tagID.String() + " refs/tags/v1\n",
- peeledID.String() + " refs/tags/v1^{}\n",
- "0000",
- }
-
- for _, part := range wantParts {
- if !strings.Contains(got, part) {
- t.Fatalf("advertisement missing %q in %q", part, got)
- }
- }
- })
-}
-
-func TestAdvertiseRefsWritesNoRefsCapabilitiesLine(t *testing.T) {
- t.Parallel()
-
- //nolint:thelper
- testgit.ForEachAlgorithm(t, func(t *testing.T, algo objectid.Algorithm) {
- t.Parallel()
-
- var out bufferWriteFlusher
-
- session := server.NewSession(
- strings.NewReader(""),
- &out,
- server.Options{
- Algorithm: algo,
- },
- )
-
- err := session.AdvertiseRefs(server.Advertisement{}, []string{
- "report-status",
- "object-format=" + algo.String(),
- })
- if err != nil {
- t.Fatalf("AdvertiseRefs: %v", err)
- }
-
- got := out.String()
-
- want := objectid.Zero(algo).String() + " capabilities^{}\x00report-status object-format=" + algo.String() + "\n"
- if !strings.Contains(got, want) {
- t.Fatalf("unexpected no-refs advertisement %q", got)
- }
- })
-}
diff --git a/protocol/v0v1/server/advertised_ref.go b/protocol/v0v1/server/advertised_ref.go
deleted file mode 100644
index cf6ddcc8..00000000
--- a/protocol/v0v1/server/advertised_ref.go
+++ /dev/null
@@ -1,22 +0,0 @@
-package server
-
-import objectid "codeberg.org/lindenii/furgit/object/id"
-
-// AdvertisedRef is one ref entry in one v0/v1 server advertisement.
-type AdvertisedRef struct {
- // Name is the advertised reference name. It may be HEAD or one full
- // reference name.
- Name string
- // ID is the object ID currently advertised for Name.
- ID objectid.ObjectID
- // Peeled is the peeled annotated-tag target when available.
- //
- // If set, advertisement writes one immediate "<name>^{}" line after the
- // main entry, matching Git's advertisement rules.
- Peeled *objectid.ObjectID
-}
-
-// Advertisement is one server-side ref advertisement.
-type Advertisement struct {
- Refs []AdvertisedRef
-}
diff --git a/protocol/v0v1/server/doc.go b/protocol/v0v1/server/doc.go
deleted file mode 100644
index ea0b3f18..00000000
--- a/protocol/v0v1/server/doc.go
+++ /dev/null
@@ -1,2 +0,0 @@
-// Package server implements shared server-side Git protocol v0/v1 framing.
-package server
diff --git a/protocol/v0v1/server/errors.go b/protocol/v0v1/server/errors.go
deleted file mode 100644
index 6a456234..00000000
--- a/protocol/v0v1/server/errors.go
+++ /dev/null
@@ -1,18 +0,0 @@
-package server
-
-// ProtocolError reports one malformed or unsupported protocol input.
-type ProtocolError struct {
- Reason string
-}
-
-// Error returns the formatted error string.
-func (err *ProtocolError) Error() string {
- return "protocol/v0v1/server: protocol error: " + err.Reason
-}
-
-// ErrUnexpectedPacket reports one unexpected pkt-line control packet.
-var ErrUnexpectedPacket = &ProtocolError{Reason: "unexpected control packet"}
-
-// ErrSideBandNotEnabled reports one attempt to write sideband frames without a
-// negotiated side-band-64k session.
-var ErrSideBandNotEnabled = &ProtocolError{Reason: "side-band-64k not enabled"}
diff --git a/protocol/v0v1/server/frame.go b/protocol/v0v1/server/frame.go
deleted file mode 100644
index 3cccba08..00000000
--- a/protocol/v0v1/server/frame.go
+++ /dev/null
@@ -1,20 +0,0 @@
-package server
-
-import "codeberg.org/lindenii/furgit/protocol/pktline"
-
-// FrameType identifies one low-level v0/v1 server pkt-line frame type.
-type FrameType = pktline.PacketType
-
-const (
- // FrameData is one data pkt-line.
- FrameData = pktline.PacketData
- // FrameFlush is one flush-pkt.
- FrameFlush = pktline.PacketFlush
- // FrameDelim is one delim-pkt.
- FrameDelim = pktline.PacketDelim
- // FrameResponseEnd is one response-end-pkt.
- FrameResponseEnd = pktline.PacketResponseEnd
-)
-
-// Frame is one decoded low-level pkt-line frame.
-type Frame = pktline.Frame
diff --git a/protocol/v0v1/server/helpers.go b/protocol/v0v1/server/helpers.go
deleted file mode 100644
index 9a62f714..00000000
--- a/protocol/v0v1/server/helpers.go
+++ /dev/null
@@ -1,29 +0,0 @@
-package server
-
-import (
- "slices"
-)
-
-func sortAdvertisedRefs(refs []AdvertisedRef) []AdvertisedRef {
- out := append([]AdvertisedRef(nil), refs...)
- slices.SortFunc(out, func(left, right AdvertisedRef) int {
- if left.Name == "HEAD" && right.Name != "HEAD" {
- return -1
- }
-
- if left.Name != "HEAD" && right.Name == "HEAD" {
- return 1
- }
-
- switch {
- case left.Name < right.Name:
- return -1
- case left.Name > right.Name:
- return 1
- default:
- return 0
- }
- })
-
- return out
-}
diff --git a/protocol/v0v1/server/helpers_test.go b/protocol/v0v1/server/helpers_test.go
deleted file mode 100644
index 261bbdc5..00000000
--- a/protocol/v0v1/server/helpers_test.go
+++ /dev/null
@@ -1,28 +0,0 @@
-package server_test
-
-import (
- "bytes"
- "strings"
- "testing"
-
- objectid "codeberg.org/lindenii/furgit/object/id"
-)
-
-type bufferWriteFlusher struct {
- bytes.Buffer
-}
-
-func (bufferWriteFlusher) Flush() error {
- return nil
-}
-
-func mustHexID(tb testing.TB, algo objectid.Algorithm, digit string) objectid.ObjectID {
- tb.Helper()
-
- id, err := objectid.ParseHex(algo, strings.Repeat(digit, algo.HexLen()))
- if err != nil {
- tb.Fatalf("objectid.ParseHex(%q): %v", strings.Repeat(digit, algo.HexLen()), err)
- }
-
- return id
-}
diff --git a/protocol/v0v1/server/receivepack/capabilities.go b/protocol/v0v1/server/receivepack/capabilities.go
deleted file mode 100644
index e0ff51a3..00000000
--- a/protocol/v0v1/server/receivepack/capabilities.go
+++ /dev/null
@@ -1,192 +0,0 @@
-package receivepack
-
-import (
- "fmt"
- "slices"
- "strings"
-
- objectid "codeberg.org/lindenii/furgit/object/id"
-)
-
-// Capabilities describes one receive-pack capability set.
-type Capabilities struct {
- ReportStatus bool
- ReportStatusV2 bool
- DeleteRefs bool
- SideBand64K bool
- Quiet bool
- Atomic bool
- OfsDelta bool
- PushOptions bool
- PushCertNonce string
- ObjectFormat objectid.Algorithm
- SessionID string
- Agent string
-}
-
-// Normalize returns one normalized copy of caps.
-func (caps Capabilities) Normalize(defaultAlgorithm objectid.Algorithm) Capabilities {
- if caps.ObjectFormat == objectid.AlgorithmUnknown {
- caps.ObjectFormat = defaultAlgorithm
- }
-
- return caps
-}
-
-// Tokens returns capabilities in Git advertisement order.
-func (caps Capabilities) Tokens(defaultAlgorithm objectid.Algorithm) []string {
- caps = caps.Normalize(defaultAlgorithm)
-
- tokens := make([]string, 0, 11)
- if caps.ReportStatus {
- tokens = append(tokens, "report-status")
- }
-
- if caps.ReportStatusV2 {
- tokens = append(tokens, "report-status-v2")
- }
-
- if caps.DeleteRefs {
- tokens = append(tokens, "delete-refs")
- }
-
- if caps.SideBand64K {
- tokens = append(tokens, "side-band-64k")
- }
-
- if caps.Quiet {
- tokens = append(tokens, "quiet")
- }
-
- if caps.Atomic {
- tokens = append(tokens, "atomic")
- }
-
- if caps.OfsDelta {
- tokens = append(tokens, "ofs-delta")
- }
-
- if caps.PushCertNonce != "" {
- tokens = append(tokens, "push-cert="+caps.PushCertNonce)
- }
-
- if caps.PushOptions {
- tokens = append(tokens, "push-options")
- }
-
- if caps.SessionID != "" {
- tokens = append(tokens, "session-id="+caps.SessionID)
- }
-
- if caps.ObjectFormat != objectid.AlgorithmUnknown {
- tokens = append(tokens, "object-format="+caps.ObjectFormat.String())
- }
-
- if caps.Agent != "" {
- tokens = append(tokens, "agent="+caps.Agent)
- }
-
- return tokens
-}
-
-func (caps Capabilities) supportsToken(token string, defaultAlgorithm objectid.Algorithm) bool {
- name, value, _ := strings.Cut(token, "=")
-
- switch name {
- case "report-status":
- return caps.ReportStatus && value == ""
- case "report-status-v2":
- return caps.ReportStatusV2 && value == ""
- case "delete-refs":
- return caps.DeleteRefs && value == ""
- case "side-band-64k":
- return caps.SideBand64K && value == ""
- case "quiet":
- return caps.Quiet && value == ""
- case "atomic":
- return caps.Atomic && value == ""
- case "ofs-delta":
- return caps.OfsDelta && value == ""
- case "push-options":
- return caps.PushOptions && value == ""
- case "push-cert":
- return caps.PushCertNonce != "" && value != ""
- case "object-format":
- if value == "" {
- return false
- }
-
- algo, ok := objectid.ParseAlgorithm(value)
-
- return ok && algo == caps.Normalize(defaultAlgorithm).ObjectFormat
- case "session-id":
- return caps.SessionID != "" && value != ""
- case "agent":
- return caps.Agent != "" && value != ""
- default:
- return false
- }
-}
-
-func parseCapabilityList(s string) ([]string, error) {
- s = strings.TrimSuffix(s, "\n")
- if s == "" {
- return nil, nil
- }
-
- tokens := strings.Fields(s)
- if slices.Contains(tokens, "") {
- return nil, &ProtocolError{Reason: "empty capability token"}
- }
-
- return tokens, nil
-}
-
-func parseRequestedCapabilities(
- tokens []string,
- supported Capabilities,
- defaultAlgorithm objectid.Algorithm,
-) (Capabilities, error) {
- var requested Capabilities
-
- requested.ObjectFormat = defaultAlgorithm
-
- for _, token := range tokens {
- if !supported.supportsToken(token, defaultAlgorithm) {
- return Capabilities{}, &ProtocolError{
- Reason: fmt.Sprintf("unsupported capability %q", token),
- }
- }
-
- name, value, _ := strings.Cut(token, "=")
- switch name {
- case "report-status":
- requested.ReportStatus = true
- case "report-status-v2":
- requested.ReportStatusV2 = true
- case "delete-refs":
- requested.DeleteRefs = true
- case "side-band-64k":
- requested.SideBand64K = true
- case "quiet":
- requested.Quiet = true
- case "atomic":
- requested.Atomic = true
- case "ofs-delta":
- requested.OfsDelta = true
- case "push-options":
- requested.PushOptions = true
- case "push-cert":
- requested.PushCertNonce = value
- case "object-format":
- algo, _ := objectid.ParseAlgorithm(value)
- requested.ObjectFormat = algo
- case "session-id":
- requested.SessionID = value
- case "agent":
- requested.Agent = value
- }
- }
-
- return requested, nil
-}
diff --git a/protocol/v0v1/server/receivepack/doc.go b/protocol/v0v1/server/receivepack/doc.go
deleted file mode 100644
index 65793831..00000000
--- a/protocol/v0v1/server/receivepack/doc.go
+++ /dev/null
@@ -1,2 +0,0 @@
-// Package receivepack implements the receive-pack-specific server side of Git protocol v0/v1.
-package receivepack
diff --git a/protocol/v0v1/server/receivepack/errors.go b/protocol/v0v1/server/receivepack/errors.go
deleted file mode 100644
index d89f8959..00000000
--- a/protocol/v0v1/server/receivepack/errors.go
+++ /dev/null
@@ -1,11 +0,0 @@
-package receivepack
-
-// ProtocolError reports one malformed or unsupported receive-pack protocol input.
-type ProtocolError struct {
- Reason string
-}
-
-// Error returns the formatted error string.
-func (err *ProtocolError) Error() string {
- return "protocol/v0v1/server/receivepack: protocol error: " + err.Reason
-}
diff --git a/protocol/v0v1/server/receivepack/helpers_test.go b/protocol/v0v1/server/receivepack/helpers_test.go
deleted file mode 100644
index 5db8e6a6..00000000
--- a/protocol/v0v1/server/receivepack/helpers_test.go
+++ /dev/null
@@ -1,28 +0,0 @@
-package receivepack_test
-
-import (
- "bytes"
- "strings"
- "testing"
-
- objectid "codeberg.org/lindenii/furgit/object/id"
-)
-
-type bufferWriteFlusher struct {
- bytes.Buffer
-}
-
-func (bufferWriteFlusher) Flush() error {
- return nil
-}
-
-func mustHexID(tb testing.TB, algo objectid.Algorithm, digit string) objectid.ObjectID {
- tb.Helper()
-
- id, err := objectid.ParseHex(algo, strings.Repeat(digit, algo.HexLen()))
- if err != nil {
- tb.Fatalf("objectid.ParseHex(%q): %v", strings.Repeat(digit, algo.HexLen()), err)
- }
-
- return id
-}
diff --git a/protocol/v0v1/server/receivepack/parse_test.go b/protocol/v0v1/server/receivepack/parse_test.go
deleted file mode 100644
index 534edcb2..00000000
--- a/protocol/v0v1/server/receivepack/parse_test.go
+++ /dev/null
@@ -1,255 +0,0 @@
-package receivepack_test
-
-import (
- "errors"
- "strings"
- "testing"
-
- "codeberg.org/lindenii/furgit/internal/testgit"
- objectid "codeberg.org/lindenii/furgit/object/id"
- "codeberg.org/lindenii/furgit/protocol/pktline"
- common "codeberg.org/lindenii/furgit/protocol/v0v1/server"
- receivepack "codeberg.org/lindenii/furgit/protocol/v0v1/server/receivepack"
-)
-
-func TestReadRequestParsesCommandsAndPushOptions(t *testing.T) {
- t.Parallel()
-
- //nolint:thelper
- testgit.ForEachAlgorithm(t, func(t *testing.T, algo objectid.Algorithm) {
- t.Parallel()
-
- oldZero := objectid.Zero(algo).String()
- oneID := mustHexID(t, algo, "1")
-
- var wire bufferWriteFlusher
-
- enc := pktline.NewEncoder(&wire)
-
- err := enc.WriteData([]byte(
- oldZero + " " + oneID.String() + " refs/heads/main\x00report-status push-options object-format=" + algo.String() + "\n",
- ))
- if err != nil {
- t.Fatalf("WriteData(first): %v", err)
- }
-
- err = enc.WriteData([]byte(
- oneID.String() + " " + oldZero + " refs/heads/old\n",
- ))
- if err != nil {
- t.Fatalf("WriteData(second): %v", err)
- }
-
- err = enc.WriteFlush()
- if err != nil {
- t.Fatalf("WriteFlush(commands): %v", err)
- }
-
- err = enc.WriteData([]byte("ci.skip\n"))
- if err != nil {
- t.Fatalf("WriteData(push-option): %v", err)
- }
-
- err = enc.WriteFlush()
- if err != nil {
- t.Fatalf("WriteFlush(push-options): %v", err)
- }
-
- base := common.NewSession(strings.NewReader(wire.String()), &bufferWriteFlusher{}, common.Options{
- Algorithm: algo,
- })
- session := receivepack.NewSession(base, receivepack.Capabilities{
- ReportStatus: true,
- PushOptions: true,
- ObjectFormat: algo,
- })
-
- req, err := session.ReadRequest()
- if err != nil {
- t.Fatalf("ReadRequest: %v", err)
- }
-
- if len(req.Commands) != 2 {
- t.Fatalf("len(req.Commands) = %d, want 2", len(req.Commands))
- }
-
- if !req.Capabilities.ReportStatus || !req.Capabilities.PushOptions {
- t.Fatalf("capabilities = %#v", req.Capabilities)
- }
-
- if len(req.PushOptions) != 1 || req.PushOptions[0] != "ci.skip" {
- t.Fatalf("push options = %#v", req.PushOptions)
- }
-
- if !req.PackExpected {
- t.Fatalf("PackExpected = false, want true")
- }
-
- if req.DeleteOnly {
- t.Fatalf("DeleteOnly = true, want false")
- }
- })
-}
-
-func TestReadRequestDeleteOnlyDoesNotExpectPack(t *testing.T) {
- t.Parallel()
-
- //nolint:thelper
- testgit.ForEachAlgorithm(t, func(t *testing.T, algo objectid.Algorithm) {
- t.Parallel()
-
- oneID := mustHexID(t, algo, "1")
-
- var wire bufferWriteFlusher
-
- enc := pktline.NewEncoder(&wire)
-
- err := enc.WriteData([]byte(
- oneID.String() + " " + objectid.Zero(algo).String() + " refs/heads/old\x00delete-refs object-format=" + algo.String() + "\n",
- ))
- if err != nil {
- t.Fatalf("WriteData: %v", err)
- }
-
- err = enc.WriteFlush()
- if err != nil {
- t.Fatalf("WriteFlush: %v", err)
- }
-
- base := common.NewSession(strings.NewReader(wire.String()), &bufferWriteFlusher{}, common.Options{
- Algorithm: algo,
- })
- session := receivepack.NewSession(base, receivepack.Capabilities{
- DeleteRefs: true,
- ObjectFormat: algo,
- })
-
- req, err := session.ReadRequest()
- if err != nil {
- t.Fatalf("ReadRequest: %v", err)
- }
-
- if req.PackExpected {
- t.Fatalf("PackExpected = true, want false")
- }
-
- if !req.DeleteOnly {
- t.Fatalf("DeleteOnly = false, want true")
- }
- })
-}
-
-func TestReadRequestRejectsUnsupportedCapability(t *testing.T) {
- t.Parallel()
-
- //nolint:thelper
- testgit.ForEachAlgorithm(t, func(t *testing.T, algo objectid.Algorithm) {
- t.Parallel()
-
- oneID := mustHexID(t, algo, "1")
-
- var wire bufferWriteFlusher
-
- enc := pktline.NewEncoder(&wire)
-
- err := enc.WriteData([]byte(
- objectid.Zero(algo).String() + " " + oneID.String() + " refs/heads/main\x00atomic object-format=" + algo.String() + "\n",
- ))
- if err != nil {
- t.Fatalf("WriteData: %v", err)
- }
-
- err = enc.WriteFlush()
- if err != nil {
- t.Fatalf("WriteFlush: %v", err)
- }
-
- base := common.NewSession(strings.NewReader(wire.String()), &bufferWriteFlusher{}, common.Options{
- Algorithm: algo,
- })
- session := receivepack.NewSession(base, receivepack.Capabilities{ObjectFormat: algo})
-
- _, err = session.ReadRequest()
- if err == nil {
- t.Fatalf("ReadRequest error = nil, want error")
- }
-
- protocolErr, ok := errors.AsType[*receivepack.ProtocolError](err)
- if !ok {
- t.Fatalf("errors.AsType[*receivepack.ProtocolError](%T) = false", err)
- }
-
- if !strings.Contains(protocolErr.Reason, "unsupported capability") {
- t.Fatalf("ProtocolError.Reason = %q", protocolErr.Reason)
- }
- })
-}
-
-func TestReadRequestParsesPushCertificate(t *testing.T) {
- t.Parallel()
-
- //nolint:thelper
- testgit.ForEachAlgorithm(t, func(t *testing.T, algo objectid.Algorithm) {
- t.Parallel()
-
- oneID := mustHexID(t, algo, "1")
-
- var wire bufferWriteFlusher
-
- enc := pktline.NewEncoder(&wire)
-
- err := enc.WriteData([]byte("push-cert\x00push-cert=nonce object-format=" + algo.String() + "\n"))
- if err != nil {
- t.Fatalf("WriteData(push-cert): %v", err)
- }
-
- lines := []string{
- "certificate version 0.1\n",
- "pusher Example <example@example.com>\n",
- "nonce nonce\n",
- "push-option ci.skip\n",
- "\n",
- objectid.Zero(algo).String() + " " + oneID.String() + " refs/heads/main\n",
- "-----BEGIN PGP SIGNATURE-----\n",
- "abcdef\n",
- "push-cert-end\n",
- }
-
- for _, line := range lines {
- err = enc.WriteData([]byte(line))
- if err != nil {
- t.Fatalf("WriteData(%q): %v", line, err)
- }
- }
-
- err = enc.WriteFlush()
- if err != nil {
- t.Fatalf("WriteFlush: %v", err)
- }
-
- base := common.NewSession(strings.NewReader(wire.String()), &bufferWriteFlusher{}, common.Options{
- Algorithm: algo,
- })
- session := receivepack.NewSession(base, receivepack.Capabilities{
- PushCertNonce: "server-nonce",
- ObjectFormat: algo,
- })
-
- req, err := session.ReadRequest()
- if err != nil {
- t.Fatalf("ReadRequest: %v", err)
- }
-
- if req.PushCert == nil {
- t.Fatalf("PushCert = nil, want parsed certificate")
- }
-
- if len(req.Commands) != 1 {
- t.Fatalf("len(req.Commands) = %d, want 1", len(req.Commands))
- }
-
- if len(req.PushCert.EmbeddedOption) != 1 || req.PushCert.EmbeddedOption[0] != "ci.skip" {
- t.Fatalf("embedded options = %#v", req.PushCert.EmbeddedOption)
- }
- })
-}
diff --git a/protocol/v0v1/server/receivepack/report_status.go b/protocol/v0v1/server/receivepack/report_status.go
deleted file mode 100644
index f6ac4985..00000000
--- a/protocol/v0v1/server/receivepack/report_status.go
+++ /dev/null
@@ -1,185 +0,0 @@
-package receivepack
-
-import (
- "fmt"
-
- "codeberg.org/lindenii/furgit/protocol/pktline"
-)
-
-// WriteReportStatus writes one classic report-status response.
-func (session *Session) WriteReportStatus(result ReportStatusResult) error {
- unpackResult := "ok"
- if result.UnpackError != "" {
- unpackResult = result.UnpackError
- }
-
- if !session.negotiated.SideBand64K {
- err := session.base.WriteData(fmt.Appendf(nil, "unpack %s\n", unpackResult))
- if err != nil {
- return err
- }
-
- for _, command := range result.Commands {
- line := fmt.Sprintf("ok %s\n", command.Name)
- if command.Error != "" {
- line = fmt.Sprintf("ng %s %s\n", command.Name, command.Error)
- }
-
- err = session.base.WriteData([]byte(line))
- if err != nil {
- return err
- }
- }
-
- return session.base.WriteFlush()
- }
-
- buf, err := pktline.AppendData(nil, fmt.Appendf(nil, "unpack %s\n", unpackResult))
- if err != nil {
- return err
- }
-
- for _, command := range result.Commands {
- line := fmt.Sprintf("ok %s\n", command.Name)
- if command.Error != "" {
- line = fmt.Sprintf("ng %s %s\n", command.Name, command.Error)
- }
-
- buf, err = pktline.AppendData(buf, []byte(line))
- if err != nil {
- return err
- }
- }
-
- buf = pktline.AppendFlushPkt(buf)
-
- w := session.base.PrimaryDataWriter()
-
- _, err = w.Write(buf)
- if err != nil {
- return err
- }
-
- return session.base.WriteFlush()
-}
-
-// WriteReportStatusV2 writes one report-status-v2 response.
-func (session *Session) WriteReportStatusV2(result ReportStatusResult) error {
- unpackResult := "ok"
- if result.UnpackError != "" {
- unpackResult = result.UnpackError
- }
-
- if !session.negotiated.SideBand64K { //nolint:nestif
- err := session.base.WriteData(fmt.Appendf(nil, "unpack %s\n", unpackResult))
- if err != nil {
- return err
- }
-
- for _, command := range result.Commands {
- if command.Error != "" {
- err = session.base.WriteData(fmt.Appendf(nil, "ng %s %s\n", command.Name, command.Error))
- if err != nil {
- return err
- }
-
- continue
- }
-
- err = session.base.WriteData(fmt.Appendf(nil, "ok %s\n", command.Name))
- if err != nil {
- return err
- }
-
- if command.RefName != "" {
- err = session.base.WriteData(fmt.Appendf(nil, "option refname %s\n", command.RefName))
- if err != nil {
- return err
- }
- }
-
- if command.OldID != nil {
- err = session.base.WriteData(fmt.Appendf(nil, "option old-oid %s\n", *command.OldID))
- if err != nil {
- return err
- }
- }
-
- if command.NewID != nil {
- err = session.base.WriteData(fmt.Appendf(nil, "option new-oid %s\n", *command.NewID))
- if err != nil {
- return err
- }
- }
-
- if command.ForcedUpdate {
- err = session.base.WriteData([]byte("option forced-update\n"))
- if err != nil {
- return err
- }
- }
- }
-
- return session.base.WriteFlush()
- }
-
- buf, err := pktline.AppendData(nil, fmt.Appendf(nil, "unpack %s\n", unpackResult))
- if err != nil {
- return err
- }
-
- for _, command := range result.Commands {
- if command.Error != "" {
- buf, err = pktline.AppendData(buf, fmt.Appendf(nil, "ng %s %s\n", command.Name, command.Error))
- if err != nil {
- return err
- }
-
- continue
- }
-
- buf, err = pktline.AppendData(buf, fmt.Appendf(nil, "ok %s\n", command.Name))
- if err != nil {
- return err
- }
-
- if command.RefName != "" {
- buf, err = pktline.AppendData(buf, fmt.Appendf(nil, "option refname %s\n", command.RefName))
- if err != nil {
- return err
- }
- }
-
- if command.OldID != nil {
- buf, err = pktline.AppendData(buf, fmt.Appendf(nil, "option old-oid %s\n", *command.OldID))
- if err != nil {
- return err
- }
- }
-
- if command.NewID != nil {
- buf, err = pktline.AppendData(buf, fmt.Appendf(nil, "option new-oid %s\n", *command.NewID))
- if err != nil {
- return err
- }
- }
-
- if command.ForcedUpdate {
- buf, err = pktline.AppendData(buf, []byte("option forced-update\n"))
- if err != nil {
- return err
- }
- }
- }
-
- buf = pktline.AppendFlushPkt(buf)
-
- w := session.base.PrimaryDataWriter()
-
- _, err = w.Write(buf)
- if err != nil {
- return err
- }
-
- return session.base.WriteFlush()
-}
diff --git a/protocol/v0v1/server/receivepack/report_status_test.go b/protocol/v0v1/server/receivepack/report_status_test.go
deleted file mode 100644
index 0f22612b..00000000
--- a/protocol/v0v1/server/receivepack/report_status_test.go
+++ /dev/null
@@ -1,293 +0,0 @@
-package receivepack_test
-
-import (
- "errors"
- "io"
- "strings"
- "testing"
-
- "codeberg.org/lindenii/furgit/internal/testgit"
- objectid "codeberg.org/lindenii/furgit/object/id"
- "codeberg.org/lindenii/furgit/protocol/pktline"
- "codeberg.org/lindenii/furgit/protocol/sideband64k"
- common "codeberg.org/lindenii/furgit/protocol/v0v1/server"
- receivepack "codeberg.org/lindenii/furgit/protocol/v0v1/server/receivepack"
-)
-
-func TestWriteReportStatusWritesClassicStatus(t *testing.T) {
- t.Parallel()
-
- var out bufferWriteFlusher
-
- base := common.NewSession(strings.NewReader(""), &out, common.Options{})
- session := receivepack.NewSession(base, receivepack.Capabilities{})
-
- err := session.WriteReportStatus(receivepack.ReportStatusResult{
- Commands: []receivepack.CommandResult{
- {Name: "refs/heads/main"},
- {Name: "refs/heads/dev", Error: "non-fast-forward"},
- },
- })
- if err != nil {
- t.Fatalf("WriteReportStatus: %v", err)
- }
-
- got := out.String()
- wantParts := []string{
- "unpack ok\n",
- "ok refs/heads/main\n",
- "ng refs/heads/dev non-fast-forward\n",
- "0000",
- }
-
- for _, part := range wantParts {
- if !strings.Contains(got, part) {
- t.Fatalf("report-status missing %q in %q", part, got)
- }
- }
-}
-
-func TestWriteReportStatusUsesSideBand64KWhenNegotiated(t *testing.T) {
- t.Parallel()
-
- //nolint:thelper
- testgit.ForEachAlgorithm(t, func(t *testing.T, algo objectid.Algorithm) {
- t.Parallel()
-
- var requestWire bufferWriteFlusher
-
- requestEnc := pktline.NewEncoder(&requestWire)
-
- err := requestEnc.WriteData([]byte(
- objectid.Zero(algo).String() + " " + mustHexID(t, algo, "1").String() + " refs/heads/main\x00report-status side-band-64k object-format=" + algo.String() + "\n",
- ))
- if err != nil {
- t.Fatalf("WriteData(request): %v", err)
- }
-
- err = requestEnc.WriteFlush()
- if err != nil {
- t.Fatalf("WriteFlush(request): %v", err)
- }
-
- var out bufferWriteFlusher
-
- base := common.NewSession(strings.NewReader(requestWire.String()), &out, common.Options{
- Algorithm: algo,
- })
- session := receivepack.NewSession(base, receivepack.Capabilities{
- ReportStatus: true,
- SideBand64K: true,
- ObjectFormat: algo,
- })
-
- _, err = session.ReadRequest()
- if err != nil {
- t.Fatalf("ReadRequest: %v", err)
- }
-
- err = session.WriteReportStatus(receivepack.ReportStatusResult{
- Commands: []receivepack.CommandResult{
- {Name: "refs/heads/main"},
- },
- })
- if err != nil {
- t.Fatalf("WriteReportStatus: %v", err)
- }
-
- dec := sideband64k.NewDecoder(strings.NewReader(out.String()), sideband64k.ReadOptions{})
-
- frame, err := dec.ReadFrame()
- if err != nil {
- t.Fatalf("ReadFrame(unpack): %v", err)
- }
-
- if frame.Type != sideband64k.FrameData {
- t.Fatalf("first frame = %#v", frame)
- }
-
- statusDec := pktline.NewDecoder(strings.NewReader(string(frame.Payload)), pktline.ReadOptions{})
-
- statusFrame, err := statusDec.ReadFrame()
- if err != nil {
- t.Fatalf("ReadFrame(unpack status): %v", err)
- }
-
- if statusFrame.Type != pktline.PacketData || string(statusFrame.Payload) != "unpack ok\n" {
- t.Fatalf("first status frame = %#v", statusFrame)
- }
-
- statusFrame, err = statusDec.ReadFrame()
- if err != nil {
- t.Fatalf("ReadFrame(ok status): %v", err)
- }
-
- if statusFrame.Type != pktline.PacketData || string(statusFrame.Payload) != "ok refs/heads/main\n" {
- t.Fatalf("second status frame = %#v", statusFrame)
- }
-
- statusFrame, err = statusDec.ReadFrame()
- if err != nil {
- t.Fatalf("ReadFrame(status flush): %v", err)
- }
-
- if statusFrame.Type != pktline.PacketFlush {
- t.Fatalf("status flush frame.Type = %v, want FrameFlush", statusFrame.Type)
- }
-
- frame, err = dec.ReadFrame()
- if err != nil {
- t.Fatalf("ReadFrame(outer flush): %v", err)
- }
-
- if frame.Type != sideband64k.FrameFlush {
- t.Fatalf("outer flush frame.Type = %v, want FrameFlush", frame.Type)
- }
- })
-}
-
-func TestWriteReportStatusV2WritesOptionLines(t *testing.T) {
- t.Parallel()
-
- //nolint:thelper
- testgit.ForEachAlgorithm(t, func(t *testing.T, algo objectid.Algorithm) {
- t.Parallel()
-
- oldID := mustHexID(t, algo, "1")
- newID := mustHexID(t, algo, "2")
-
- var out bufferWriteFlusher
-
- base := common.NewSession(strings.NewReader(""), &out, common.Options{})
- session := receivepack.NewSession(base, receivepack.Capabilities{})
-
- err := session.WriteReportStatusV2(receivepack.ReportStatusResult{
- Commands: []receivepack.CommandResult{
- {
- Name: "refs/pseudo/proc",
- RefName: "refs/heads/main",
- OldID: &oldID,
- NewID: &newID,
- ForcedUpdate: true,
- },
- {Name: "refs/heads/dev", Error: "rejected"},
- },
- })
- if err != nil {
- t.Fatalf("WriteReportStatusV2: %v", err)
- }
-
- got := out.String()
- wantParts := []string{
- "unpack ok\n",
- "ok refs/pseudo/proc\n",
- "option refname refs/heads/main\n",
- "option old-oid " + oldID.String() + "\n",
- "option new-oid " + newID.String() + "\n",
- "option forced-update\n",
- "ng refs/heads/dev rejected\n",
- "0000",
- }
-
- for _, part := range wantParts {
- if !strings.Contains(got, part) {
- t.Fatalf("report-status-v2 missing %q in %q", part, got)
- }
- }
- })
-}
-
-func TestWriteProgressRequiresSideBand64K(t *testing.T) {
- t.Parallel()
-
- base := common.NewSession(strings.NewReader(""), &bufferWriteFlusher{}, common.Options{})
- session := receivepack.NewSession(base, receivepack.Capabilities{})
-
- err := session.WriteProgress([]byte("progress\n"))
- if !errors.Is(err, common.ErrSideBandNotEnabled) {
- t.Fatalf("WriteProgress error = %v, want %v", err, common.ErrSideBandNotEnabled)
- }
-}
-
-func TestProgressWriterDiscardsWithoutSideBand64K(t *testing.T) {
- t.Parallel()
-
- var out bufferWriteFlusher
-
- base := common.NewSession(strings.NewReader(""), &out, common.Options{})
- session := receivepack.NewSession(base, receivepack.Capabilities{})
-
- n, err := io.WriteString(session.ProgressWriter(), "progress line\n")
- if err != nil {
- t.Fatalf("ProgressWriter.Write: %v", err)
- }
-
- if n != len("progress line\n") {
- t.Fatalf("ProgressWriter.Write n = %d, want %d", n, len("progress line\n"))
- }
-
- if out.String() != "" {
- t.Fatalf("unexpected wire output without side-band-64k: %q", out.String())
- }
-}
-
-func TestProgressWriterUsesSideBand64KWhenNegotiated(t *testing.T) {
- t.Parallel()
-
- //nolint:thelper
- testgit.ForEachAlgorithm(t, func(t *testing.T, algo objectid.Algorithm) {
- t.Parallel()
-
- var requestWire bufferWriteFlusher
-
- requestEnc := pktline.NewEncoder(&requestWire)
-
- err := requestEnc.WriteData([]byte(
- objectid.Zero(algo).String() + " " + mustHexID(t, algo, "1").String() + " refs/heads/main\x00report-status side-band-64k object-format=" + algo.String() + "\n",
- ))
- if err != nil {
- t.Fatalf("WriteData(request): %v", err)
- }
-
- err = requestEnc.WriteFlush()
- if err != nil {
- t.Fatalf("WriteFlush(request): %v", err)
- }
-
- var out bufferWriteFlusher
-
- base := common.NewSession(strings.NewReader(requestWire.String()), &out, common.Options{
- Algorithm: algo,
- })
- session := receivepack.NewSession(base, receivepack.Capabilities{
- ReportStatus: true,
- SideBand64K: true,
- ObjectFormat: algo,
- })
-
- _, err = session.ReadRequest()
- if err != nil {
- t.Fatalf("ReadRequest: %v", err)
- }
-
- _, err = io.WriteString(session.ProgressWriter(), "remote: stage 1\r")
- if err != nil {
- t.Fatalf("ProgressWriter.Write: %v", err)
- }
-
- dec := sideband64k.NewDecoder(strings.NewReader(out.String()), sideband64k.ReadOptions{})
-
- frame, err := dec.ReadFrame()
- if err != nil {
- t.Fatalf("ReadFrame(progress): %v", err)
- }
-
- if frame.Type != sideband64k.FrameProgress {
- t.Fatalf("frame.Type = %v, want FrameProgress", frame.Type)
- }
-
- if string(frame.Payload) != "remote: stage 1\r" {
- t.Fatalf("frame.Payload = %q, want %q", frame.Payload, "remote: stage 1\r")
- }
- })
-}
diff --git a/protocol/v0v1/server/receivepack/session.go b/protocol/v0v1/server/receivepack/session.go
deleted file mode 100644
index 1ea4ab35..00000000
--- a/protocol/v0v1/server/receivepack/session.go
+++ /dev/null
@@ -1,295 +0,0 @@
-package receivepack
-
-import (
- "fmt"
- "io"
- "strings"
-
- objectid "codeberg.org/lindenii/furgit/object/id"
- common "codeberg.org/lindenii/furgit/protocol/v0v1/server"
-)
-
-// Session is one stateful server-side receive-pack protocol session.
-type Session struct {
- base *common.Session
- supported Capabilities
- negotiated Capabilities
-}
-
-// NewSession creates one receive-pack session over one common server session.
-func NewSession(base *common.Session, supported Capabilities) *Session {
- return &Session{
- base: base,
- supported: supported,
- }
-}
-
-// AdvertiseRefs writes one receive-pack ref advertisement.
-func (session *Session) AdvertiseRefs(ad common.Advertisement) error {
- return session.base.AdvertiseRefs(ad, session.supported.Tokens(session.base.Algorithm()))
-}
-
-// ReadRequest reads one receive-pack request through optional push-options.
-func (session *Session) ReadRequest() (*Request, error) {
- req := &Request{}
-
- var sawCommands bool
-
- for {
- frame, err := session.base.ReadFrame()
- if err != nil {
- return nil, err
- }
-
- switch frame.Type {
- case common.FrameFlush:
- goto afterCommands
- case common.FrameData:
- case common.FrameDelim, common.FrameResponseEnd:
- return nil, &ProtocolError{Reason: fmt.Sprintf("unexpected packet type %v", frame.Type)}
- }
-
- payload := string(frame.Payload)
- if strings.HasPrefix(payload, "shallow ") {
- line := trimOneLF(payload)
-
- shallowID, err := parseObjectID(session.base.Algorithm(), line[len("shallow "):])
- if err != nil {
- return nil, err
- }
-
- req.Shallow = append(req.Shallow, shallowID)
-
- continue
- }
-
- if strings.HasPrefix(payload, "push-cert\x00") {
- if sawCommands {
- return nil, &ProtocolError{Reason: "got both push certificate and unsigned commands"}
- }
-
- capabilityTokens, err := parseCapabilityList(payload[len("push-cert\x00"):])
- if err != nil {
- return nil, err
- }
-
- requested, err := parseRequestedCapabilities(
- capabilityTokens,
- session.supported,
- session.base.Algorithm(),
- )
- if err != nil {
- return nil, err
- }
-
- req.Capabilities = requested
-
- cert, err := session.readPushCertificate()
- if err != nil {
- return nil, err
- }
-
- req.PushCert = cert
- req.Commands = append(req.Commands, cert.Commands...)
- sawCommands = true
-
- continue
- }
-
- line := trimOneLF(payload)
- if !sawCommands && strings.Contains(line, "\x00") {
- commandPart, capPart, _ := strings.Cut(line, "\x00")
-
- capabilityTokens, err := parseCapabilityList(capPart)
- if err != nil {
- return nil, err
- }
-
- requested, err := parseRequestedCapabilities(
- capabilityTokens,
- session.supported,
- session.base.Algorithm(),
- )
- if err != nil {
- return nil, err
- }
-
- req.Capabilities = requested
- line = commandPart
- }
-
- cmd, err := parseCommand(session.base.Algorithm(), line)
- if err != nil {
- return nil, err
- }
-
- req.Commands = append(req.Commands, cmd)
- sawCommands = true
- }
-
-afterCommands:
- if req.Capabilities.PushOptions {
- for {
- frame, err := session.base.ReadFrame()
- if err != nil {
- return nil, err
- }
-
- switch frame.Type {
- case common.FrameFlush:
- goto afterPushOptions
- case common.FrameData:
- req.PushOptions = append(req.PushOptions, trimOneLF(string(frame.Payload)))
- case common.FrameDelim, common.FrameResponseEnd:
- return nil, &ProtocolError{Reason: fmt.Sprintf("unexpected packet type %v", frame.Type)}
- }
- }
- }
-
-afterPushOptions:
- req.DeleteOnly = deleteOnly(req.Commands)
-
- req.PackExpected = len(req.Commands) > 0 && !req.DeleteOnly
-
- session.negotiated = req.Capabilities
-
- if req.Capabilities.SideBand64K {
- session.base.EnableSideBand64K()
- }
-
- return req, nil
-}
-
-// WriteProgress writes one progress packet.
-func (session *Session) WriteProgress(p []byte) error {
- return session.base.WriteProgress(p)
-}
-
-// ProgressWriter returns one chunking writer for sideband progress output.
-//
-// When side-band-64k was not negotiated, writes are discarded.
-func (session *Session) ProgressWriter() io.Writer {
- return session.base.ProgressWriter()
-}
-
-// WriteError writes one fatal error packet.
-func (session *Session) WriteError(p []byte) error {
- return session.base.WriteError(p)
-}
-
-// ErrorWriter returns one chunking writer for sideband error output.
-//
-// When side-band-64k was not negotiated, writes are discarded.
-func (session *Session) ErrorWriter() io.Writer {
- return session.base.ErrorWriter()
-}
-
-func trimOneLF(s string) string {
- return strings.TrimSuffix(s, "\n")
-}
-
-func parseObjectID(algo objectid.Algorithm, s string) (objectid.ObjectID, error) {
- id, err := objectid.ParseHex(algo, s)
- if err != nil {
- return objectid.ObjectID{}, &ProtocolError{
- Reason: fmt.Sprintf("invalid object id %q", s),
- }
- }
-
- return id, nil
-}
-
-func commandIsDelete(cmd Command) bool {
- return cmd.NewID == objectid.Zero(cmd.NewID.Algorithm())
-}
-
-func deleteOnly(commands []Command) bool {
- if len(commands) == 0 {
- return false
- }
-
- for _, cmd := range commands {
- if !commandIsDelete(cmd) {
- return false
- }
- }
-
- return true
-}
-
-func parseCommand(algo objectid.Algorithm, line string) (Command, error) {
- fields := strings.Fields(line)
- if len(fields) != 3 {
- return Command{}, &ProtocolError{Reason: fmt.Sprintf("malformed command %q", line)}
- }
-
- oldID, err := parseObjectID(algo, fields[0])
- if err != nil {
- return Command{}, err
- }
-
- newID, err := parseObjectID(algo, fields[1])
- if err != nil {
- return Command{}, err
- }
-
- return Command{OldID: oldID, NewID: newID, Name: fields[2]}, nil
-}
-
-func (session *Session) readPushCertificate() (*PushCertificate, error) {
- cert := &PushCertificate{}
- inCommands := false
- inSignature := false
-
- for {
- frame, err := session.base.ReadFrame()
- if err != nil {
- return nil, err
- }
-
- switch frame.Type {
- case common.FrameFlush:
- return nil, &ProtocolError{Reason: "unexpected flush inside push certificate"}
- case common.FrameData:
- case common.FrameDelim, common.FrameResponseEnd:
- return nil, &ProtocolError{Reason: fmt.Sprintf("unexpected packet type %v", frame.Type)}
- }
-
- line := string(frame.Payload)
- if line == "push-cert-end\n" {
- return cert, nil
- }
-
- if !inCommands {
- if line == "\n" {
- inCommands = true
-
- continue
- }
-
- trimmed := trimOneLF(line)
- cert.HeaderLines = append(cert.HeaderLines, trimmed)
-
- if strings.HasPrefix(trimmed, "push-option ") {
- cert.EmbeddedOption = append(cert.EmbeddedOption, trimmed[len("push-option "):])
- }
-
- continue
- }
-
- if !inSignature {
- trimmed := trimOneLF(line)
-
- cmd, err := parseCommand(session.base.Algorithm(), trimmed)
- if err == nil {
- cert.Commands = append(cert.Commands, cmd)
-
- continue
- }
-
- inSignature = true
- }
-
- cert.SignatureLines = append(cert.SignatureLines, trimOneLF(line))
- }
-}
diff --git a/protocol/v0v1/server/receivepack/types.go b/protocol/v0v1/server/receivepack/types.go
deleted file mode 100644
index b281a86b..00000000
--- a/protocol/v0v1/server/receivepack/types.go
+++ /dev/null
@@ -1,45 +0,0 @@
-package receivepack
-
-import objectid "codeberg.org/lindenii/furgit/object/id"
-
-// Command is one requested reference update.
-type Command struct {
- OldID objectid.ObjectID
- NewID objectid.ObjectID
- Name string
-}
-
-// PushCertificate is one parsed push certificate block.
-type PushCertificate struct {
- HeaderLines []string
- EmbeddedOption []string
- Commands []Command
- SignatureLines []string
-}
-
-// Request is one parsed receive-pack request.
-type Request struct {
- Capabilities Capabilities
- Shallow []objectid.ObjectID
- Commands []Command
- PushCert *PushCertificate
- PushOptions []string
- PackExpected bool
- DeleteOnly bool
-}
-
-// CommandResult is one per-command report-status result.
-type CommandResult struct {
- Name string
- Error string
- RefName string
- OldID *objectid.ObjectID
- NewID *objectid.ObjectID
- ForcedUpdate bool
-}
-
-// ReportStatusResult is one report-status payload.
-type ReportStatusResult struct {
- UnpackError string
- Commands []CommandResult
-}
diff --git a/protocol/v0v1/server/session.go b/protocol/v0v1/server/session.go
deleted file mode 100644
index 81939540..00000000
--- a/protocol/v0v1/server/session.go
+++ /dev/null
@@ -1,131 +0,0 @@
-package server
-
-import (
- "io"
-
- objectid "codeberg.org/lindenii/furgit/object/id"
- "codeberg.org/lindenii/furgit/protocol/pktline"
- "codeberg.org/lindenii/furgit/protocol/sideband64k"
-)
-
-// Options configures one server-side v0/v1 session.
-type Options struct {
- // Version selects protocol v0 or v1 framing.
- Version Version
- // Algorithm is the repository object ID algorithm for this session.
- Algorithm objectid.Algorithm
-}
-
-// Session is one stateful server-side v0/v1 server protocol session.
-type Session struct {
- dec *pktline.Decoder
- enc *pktline.Encoder
- sideband *sideband64k.Encoder
- opts Options
- useSideBand bool
-}
-
-// NewSession creates one v0/v1 server session over r and w.
-func NewSession(r io.Reader, w pktline.WriteFlusher, opts Options) *Session {
- return &Session{
- dec: pktline.NewDecoder(r, pktline.ReadOptions{}),
- enc: pktline.NewEncoder(w),
- sideband: sideband64k.NewEncoder(w),
- opts: opts,
- }
-}
-
-// Algorithm returns the session object ID algorithm.
-func (session *Session) Algorithm() objectid.Algorithm {
- return session.opts.Algorithm
-}
-
-// ReadFrame reads one low-level pkt-line frame from the session input.
-func (session *Session) ReadFrame() (Frame, error) {
- return session.dec.ReadFrame()
-}
-
-// EnableSideBand64K enables side-band-64k output framing for subsequent data,
-// progress, error, and flush writes.
-func (session *Session) EnableSideBand64K() {
- session.useSideBand = true
-}
-
-// WriteData writes one primary output packet.
-func (session *Session) WriteData(p []byte) error {
- if session.useSideBand {
- return session.sideband.WriteData(p)
- }
-
- return session.enc.WriteData(p)
-}
-
-// WriteProgress writes one progress packet.
-func (session *Session) WriteProgress(p []byte) error {
- if !session.useSideBand {
- return ErrSideBandNotEnabled
- }
-
- return session.sideband.WriteProgress(p)
-}
-
-// WriteError writes one fatal error packet.
-func (session *Session) WriteError(p []byte) error {
- if !session.useSideBand {
- return ErrSideBandNotEnabled
- }
-
- return session.sideband.WriteError(p)
-}
-
-// WriteFlush writes one trailing flush packet.
-func (session *Session) WriteFlush() error {
- if session.useSideBand {
- return session.sideband.WriteFlush()
- }
-
- return session.enc.WriteFlush()
-}
-
-// FlushIO flushes buffered transport output without emitting pkt-line frames.
-func (session *Session) FlushIO() error {
- if session.useSideBand {
- return session.sideband.FlushIO()
- }
-
- return session.enc.FlushIO()
-}
-
-// ProgressWriter returns one chunking writer for sideband progress output.
-//
-// When side-band-64k was not negotiated, writes are discarded.
-func (session *Session) ProgressWriter() io.Writer {
- if !session.useSideBand {
- return io.Discard
- }
-
- return sideband64k.NewChunkWriter(session.sideband, sideband64k.BandProgress)
-}
-
-// ErrorWriter returns one chunking writer for sideband error output.
-//
-// When side-band-64k was not negotiated, writes are discarded.
-func (session *Session) ErrorWriter() io.Writer {
- if !session.useSideBand {
- return io.Discard
- }
-
- return sideband64k.NewChunkWriter(session.sideband, sideband64k.BandError)
-}
-
-// PrimaryDataWriter returns one chunking writer for primary output bytes.
-//
-// When side-band-64k is enabled, writes are chunked into band-1 sideband
-// frames. Otherwise writes are chunked into direct pkt-line data frames.
-func (session *Session) PrimaryDataWriter() io.Writer {
- if session.useSideBand {
- return sideband64k.NewChunkWriter(session.sideband, sideband64k.BandData)
- }
-
- return pktline.NewChunkWriter(session.enc)
-}
diff --git a/protocol/v0v1/server/version.go b/protocol/v0v1/server/version.go
deleted file mode 100644
index 23ae9466..00000000
--- a/protocol/v0v1/server/version.go
+++ /dev/null
@@ -1,12 +0,0 @@
-package server
-
-// Version identifies the protocol version used on one v0/v1 server session.
-type Version uint8
-
-const (
- // Version0 is the original protocol framing with no leading version line.
- Version0 Version = iota
- // Version1 is protocol v1, which is v0 plus one leading "version 1\n"
- // pkt-line before ref advertisement.
- Version1
-)