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] }