mirror of
https://github.com/go-gitea/gitea.git
synced 2024-10-19 06:43:41 -04:00
197 lines
4.1 KiB
Go
197 lines
4.1 KiB
Go
|
package capability
|
||
|
|
||
|
import (
|
||
|
"bytes"
|
||
|
"errors"
|
||
|
"fmt"
|
||
|
"strings"
|
||
|
)
|
||
|
|
||
|
var (
|
||
|
// ErrArgumentsRequired is returned if no arguments are giving with a
|
||
|
// capability that requires arguments
|
||
|
ErrArgumentsRequired = errors.New("arguments required")
|
||
|
// ErrArguments is returned if arguments are given with a capabilities that
|
||
|
// not supports arguments
|
||
|
ErrArguments = errors.New("arguments not allowed")
|
||
|
// ErrEmtpyArgument is returned when an empty value is given
|
||
|
ErrEmtpyArgument = errors.New("empty argument")
|
||
|
// ErrMultipleArguments multiple argument given to a capabilities that not
|
||
|
// support it
|
||
|
ErrMultipleArguments = errors.New("multiple arguments not allowed")
|
||
|
)
|
||
|
|
||
|
// List represents a list of capabilities
|
||
|
type List struct {
|
||
|
m map[Capability]*entry
|
||
|
sort []string
|
||
|
}
|
||
|
|
||
|
type entry struct {
|
||
|
Name Capability
|
||
|
Values []string
|
||
|
}
|
||
|
|
||
|
// NewList returns a new List of capabilities
|
||
|
func NewList() *List {
|
||
|
return &List{
|
||
|
m: make(map[Capability]*entry),
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// IsEmpty returns true if the List is empty
|
||
|
func (l *List) IsEmpty() bool {
|
||
|
return len(l.sort) == 0
|
||
|
}
|
||
|
|
||
|
// Decode decodes list of capabilities from raw into the list
|
||
|
func (l *List) Decode(raw []byte) error {
|
||
|
// git 1.x receive pack used to send a leading space on its
|
||
|
// git-receive-pack capabilities announcement. We just trim space to be
|
||
|
// tolerant to space changes in different versions.
|
||
|
raw = bytes.TrimSpace(raw)
|
||
|
|
||
|
if len(raw) == 0 {
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
for _, data := range bytes.Split(raw, []byte{' '}) {
|
||
|
pair := bytes.SplitN(data, []byte{'='}, 2)
|
||
|
|
||
|
c := Capability(pair[0])
|
||
|
if len(pair) == 1 {
|
||
|
if err := l.Add(c); err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
continue
|
||
|
}
|
||
|
|
||
|
if err := l.Add(c, string(pair[1])); err != nil {
|
||
|
return err
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
// Get returns the values for a capability
|
||
|
func (l *List) Get(capability Capability) []string {
|
||
|
if _, ok := l.m[capability]; !ok {
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
return l.m[capability].Values
|
||
|
}
|
||
|
|
||
|
// Set sets a capability removing the previous values
|
||
|
func (l *List) Set(capability Capability, values ...string) error {
|
||
|
if _, ok := l.m[capability]; ok {
|
||
|
delete(l.m, capability)
|
||
|
}
|
||
|
|
||
|
return l.Add(capability, values...)
|
||
|
}
|
||
|
|
||
|
// Add adds a capability, values are optional
|
||
|
func (l *List) Add(c Capability, values ...string) error {
|
||
|
if err := l.validate(c, values); err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
if !l.Supports(c) {
|
||
|
l.m[c] = &entry{Name: c}
|
||
|
l.sort = append(l.sort, c.String())
|
||
|
}
|
||
|
|
||
|
if len(values) == 0 {
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
if known[c] && !multipleArgument[c] && len(l.m[c].Values) > 0 {
|
||
|
return ErrMultipleArguments
|
||
|
}
|
||
|
|
||
|
l.m[c].Values = append(l.m[c].Values, values...)
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
func (l *List) validateNoEmptyArgs(values []string) error {
|
||
|
for _, v := range values {
|
||
|
if v == "" {
|
||
|
return ErrEmtpyArgument
|
||
|
}
|
||
|
}
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
func (l *List) validate(c Capability, values []string) error {
|
||
|
if !known[c] {
|
||
|
return l.validateNoEmptyArgs(values)
|
||
|
}
|
||
|
if requiresArgument[c] && len(values) == 0 {
|
||
|
return ErrArgumentsRequired
|
||
|
}
|
||
|
|
||
|
if !requiresArgument[c] && len(values) != 0 {
|
||
|
return ErrArguments
|
||
|
}
|
||
|
|
||
|
if !multipleArgument[c] && len(values) > 1 {
|
||
|
return ErrMultipleArguments
|
||
|
}
|
||
|
return l.validateNoEmptyArgs(values)
|
||
|
}
|
||
|
|
||
|
// Supports returns true if capability is present
|
||
|
func (l *List) Supports(capability Capability) bool {
|
||
|
_, ok := l.m[capability]
|
||
|
return ok
|
||
|
}
|
||
|
|
||
|
// Delete deletes a capability from the List
|
||
|
func (l *List) Delete(capability Capability) {
|
||
|
if !l.Supports(capability) {
|
||
|
return
|
||
|
}
|
||
|
|
||
|
delete(l.m, capability)
|
||
|
for i, c := range l.sort {
|
||
|
if c != string(capability) {
|
||
|
continue
|
||
|
}
|
||
|
|
||
|
l.sort = append(l.sort[:i], l.sort[i+1:]...)
|
||
|
return
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// All returns a slice with all defined capabilities.
|
||
|
func (l *List) All() []Capability {
|
||
|
var cs []Capability
|
||
|
for _, key := range l.sort {
|
||
|
cs = append(cs, Capability(key))
|
||
|
}
|
||
|
|
||
|
return cs
|
||
|
}
|
||
|
|
||
|
// String generates the capabilities strings, the capabilities are sorted in
|
||
|
// insertion order
|
||
|
func (l *List) String() string {
|
||
|
var o []string
|
||
|
for _, key := range l.sort {
|
||
|
cap := l.m[Capability(key)]
|
||
|
if len(cap.Values) == 0 {
|
||
|
o = append(o, key)
|
||
|
continue
|
||
|
}
|
||
|
|
||
|
for _, value := range cap.Values {
|
||
|
o = append(o, fmt.Sprintf("%s=%s", key, value))
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return strings.Join(o, " ")
|
||
|
}
|