aboutsummaryrefslogtreecommitdiffstats
path: root/plumbing/protocol/packp/updreq.go
blob: 46ad6fdc9fc2c5cbdf2f69d32ce230796c9d814e (plain) (blame)
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
package packp

import (
	"errors"
	"io"

	"github.com/go-git/go-git/v5/plumbing"
	"github.com/go-git/go-git/v5/plumbing/protocol/packp/capability"
	"github.com/go-git/go-git/v5/plumbing/protocol/packp/sideband"
)

var (
	ErrEmptyCommands    = errors.New("commands cannot be empty")
	ErrMalformedCommand = errors.New("malformed command")
)

// ReferenceUpdateRequest values represent reference upload requests.
// Values from this type are not zero-value safe, use the New function instead.
type ReferenceUpdateRequest struct {
	Capabilities *capability.List
	Commands     []*Command
	Options      []*Option
	Shallow      *plumbing.Hash
	// Packfile contains an optional packfile reader.
	Packfile io.ReadCloser

	// Progress receives sideband progress messages from the server
	Progress sideband.Progress
}

// New returns a pointer to a new ReferenceUpdateRequest value.
func NewReferenceUpdateRequest() *ReferenceUpdateRequest {
	return &ReferenceUpdateRequest{
		// TODO: Add support for push-cert
		Capabilities: capability.NewList(),
		Commands:     nil,
	}
}

// NewReferenceUpdateRequestFromCapabilities returns a pointer to a new
// ReferenceUpdateRequest value, the request capabilities are filled with the
// most optimal ones, based on the adv value (advertised capabilities), the
// ReferenceUpdateRequest contains no commands
//
// It does set the following capabilities:
//   - agent
//   - report-status
//   - ofs-delta
//   - ref-delta
//   - delete-refs
// It leaves up to the user to add the following capabilities later:
//   - atomic
//   - ofs-delta
//   - side-band
//   - side-band-64k
//   - quiet
//   - push-cert
func NewReferenceUpdateRequestFromCapabilities(adv *capability.List) *ReferenceUpdateRequest {
	r := NewReferenceUpdateRequest()

	if adv.Supports(capability.Agent) {
		r.Capabilities.Set(capability.Agent, capability.DefaultAgent)
	}

	if adv.Supports(capability.ReportStatus) {
		r.Capabilities.Set(capability.ReportStatus)
	}

	return r
}

func (req *ReferenceUpdateRequest) validate() error {
	if len(req.Commands) == 0 {
		return ErrEmptyCommands
	}

	for _, c := range req.Commands {
		if err := c.validate(); err != nil {
			return err
		}
	}

	return nil
}

type Action string

const (
	Create  Action = "create"
	Update         = "update"
	Delete         = "delete"
	Invalid        = "invalid"
)

type Command struct {
	Name plumbing.ReferenceName
	Old  plumbing.Hash
	New  plumbing.Hash
}

func (c *Command) Action() Action {
	if c.Old == plumbing.ZeroHash && c.New == plumbing.ZeroHash {
		return Invalid
	}

	if c.Old == plumbing.ZeroHash {
		return Create
	}

	if c.New == plumbing.ZeroHash {
		return Delete
	}

	return Update
}

func (c *Command) validate() error {
	if c.Action() == Invalid {
		return ErrMalformedCommand
	}

	return nil
}

type Option struct {
	Key   string
	Value string
}