diff options
Diffstat (limited to 'plumbing/protocol/packp/capabilities.go')
-rw-r--r-- | plumbing/protocol/packp/capabilities.go | 136 |
1 files changed, 136 insertions, 0 deletions
diff --git a/plumbing/protocol/packp/capabilities.go b/plumbing/protocol/packp/capabilities.go new file mode 100644 index 0000000..d77c2fa --- /dev/null +++ b/plumbing/protocol/packp/capabilities.go @@ -0,0 +1,136 @@ +package packp + +import ( + "fmt" + "sort" + "strings" +) + +// Capabilities contains all the server capabilities +// https://github.com/git/git/blob/master/Documentation/technical/protocol-capabilities.txt +type Capabilities struct { + m map[string]*Capability + o []string +} + +// Capability represents a server capability +type Capability struct { + Name string + Values []string +} + +// NewCapabilities returns a new Capabilities struct +func NewCapabilities() *Capabilities { + return &Capabilities{ + m: make(map[string]*Capability), + } +} + +func (c *Capabilities) IsEmpty() bool { + return len(c.o) == 0 +} + +// Decode decodes a string +func (c *Capabilities) Decode(raw string) { + params := strings.Split(raw, " ") + for _, p := range params { + s := strings.SplitN(p, "=", 2) + + var value string + if len(s) == 2 { + value = s[1] + } + + c.Add(s[0], value) + } +} + +// Get returns the values for a capability +func (c *Capabilities) Get(capability string) *Capability { + return c.m[capability] +} + +// Set sets a capability removing the values +func (c *Capabilities) Set(capability string, values ...string) { + if _, ok := c.m[capability]; ok { + delete(c.m, capability) + } + + c.Add(capability, values...) +} + +// Add adds a capability, values are optional +func (c *Capabilities) Add(capability string, values ...string) { + if !c.Supports(capability) { + c.m[capability] = &Capability{Name: capability} + c.o = append(c.o, capability) + } + + if len(values) == 0 { + return + } + + c.m[capability].Values = append(c.m[capability].Values, values...) +} + +// Supports returns true if capability is present +func (c *Capabilities) Supports(capability string) bool { + _, ok := c.m[capability] + return ok +} + +// SymbolicReference returns the reference for a given symbolic reference +func (c *Capabilities) SymbolicReference(sym string) string { + if !c.Supports("symref") { + return "" + } + + for _, symref := range c.Get("symref").Values { + parts := strings.Split(symref, ":") + if len(parts) != 2 { + continue + } + + if parts[0] == sym { + return parts[1] + } + } + + return "" +} + +// Sorts capabilities in increasing order of their name +func (c *Capabilities) Sort() { + sort.Strings(c.o) +} + +func (c *Capabilities) String() string { + if len(c.o) == 0 { + return "" + } + + var o string + for _, key := range c.o { + cap := c.m[key] + + added := false + for _, value := range cap.Values { + if value == "" { + continue + } + + added = true + o += fmt.Sprintf("%s=%s ", key, value) + } + + if len(cap.Values) == 0 || !added { + o += key + " " + } + } + + if len(o) == 0 { + return o + } + + return o[:len(o)-1] +} |