summaryrefslogtreecommitdiffstats
path: root/vendor/gopkg.in/src-d/go-git.v4/config/refspec.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/gopkg.in/src-d/go-git.v4/config/refspec.go')
-rw-r--r--vendor/gopkg.in/src-d/go-git.v4/config/refspec.go143
1 files changed, 143 insertions, 0 deletions
diff --git a/vendor/gopkg.in/src-d/go-git.v4/config/refspec.go b/vendor/gopkg.in/src-d/go-git.v4/config/refspec.go
new file mode 100644
index 0000000000..391705cccc
--- /dev/null
+++ b/vendor/gopkg.in/src-d/go-git.v4/config/refspec.go
@@ -0,0 +1,143 @@
+package config
+
+import (
+ "errors"
+ "strings"
+
+ "gopkg.in/src-d/go-git.v4/plumbing"
+)
+
+const (
+ refSpecWildcard = "*"
+ refSpecForce = "+"
+ refSpecSeparator = ":"
+)
+
+var (
+ ErrRefSpecMalformedSeparator = errors.New("malformed refspec, separators are wrong")
+ ErrRefSpecMalformedWildcard = errors.New("malformed refspec, mismatched number of wildcards")
+)
+
+// RefSpec is a mapping from local branches to remote references
+// The format of the refspec is an optional +, followed by <src>:<dst>, where
+// <src> is the pattern for references on the remote side and <dst> is where
+// those references will be written locally. The + tells Git to update the
+// reference even if it isn’t a fast-forward.
+// eg.: "+refs/heads/*:refs/remotes/origin/*"
+//
+// https://git-scm.com/book/es/v2/Git-Internals-The-Refspec
+type RefSpec string
+
+// Validate validates the RefSpec
+func (s RefSpec) Validate() error {
+ spec := string(s)
+ if strings.Count(spec, refSpecSeparator) != 1 {
+ return ErrRefSpecMalformedSeparator
+ }
+
+ sep := strings.Index(spec, refSpecSeparator)
+ if sep == len(spec)-1 {
+ return ErrRefSpecMalformedSeparator
+ }
+
+ ws := strings.Count(spec[0:sep], refSpecWildcard)
+ wd := strings.Count(spec[sep+1:], refSpecWildcard)
+ if ws == wd && ws < 2 && wd < 2 {
+ return nil
+ }
+
+ return ErrRefSpecMalformedWildcard
+}
+
+// IsForceUpdate returns if update is allowed in non fast-forward merges.
+func (s RefSpec) IsForceUpdate() bool {
+ return s[0] == refSpecForce[0]
+}
+
+// IsDelete returns true if the refspec indicates a delete (empty src).
+func (s RefSpec) IsDelete() bool {
+ return s[0] == refSpecSeparator[0]
+}
+
+// Src return the src side.
+func (s RefSpec) Src() string {
+ spec := string(s)
+
+ var start int
+ if s.IsForceUpdate() {
+ start = 1
+ } else {
+ start = 0
+ }
+ end := strings.Index(spec, refSpecSeparator)
+
+ return spec[start:end]
+}
+
+// Match match the given plumbing.ReferenceName against the source.
+func (s RefSpec) Match(n plumbing.ReferenceName) bool {
+ if !s.IsWildcard() {
+ return s.matchExact(n)
+ }
+
+ return s.matchGlob(n)
+}
+
+// IsWildcard returns true if the RefSpec contains a wildcard.
+func (s RefSpec) IsWildcard() bool {
+ return strings.Contains(string(s), refSpecWildcard)
+}
+
+func (s RefSpec) matchExact(n plumbing.ReferenceName) bool {
+ return s.Src() == n.String()
+}
+
+func (s RefSpec) matchGlob(n plumbing.ReferenceName) bool {
+ src := s.Src()
+ name := n.String()
+ wildcard := strings.Index(src, refSpecWildcard)
+
+ var prefix, suffix string
+ prefix = src[0:wildcard]
+ if len(src) < wildcard {
+ suffix = src[wildcard+1 : len(suffix)]
+ }
+
+ return len(name) > len(prefix)+len(suffix) &&
+ strings.HasPrefix(name, prefix) &&
+ strings.HasSuffix(name, suffix)
+}
+
+// Dst returns the destination for the given remote reference.
+func (s RefSpec) Dst(n plumbing.ReferenceName) plumbing.ReferenceName {
+ spec := string(s)
+ start := strings.Index(spec, refSpecSeparator) + 1
+ dst := spec[start:]
+ src := s.Src()
+
+ if !s.IsWildcard() {
+ return plumbing.ReferenceName(dst)
+ }
+
+ name := n.String()
+ ws := strings.Index(src, refSpecWildcard)
+ wd := strings.Index(dst, refSpecWildcard)
+ match := name[ws : len(name)-(len(src)-(ws+1))]
+
+ return plumbing.ReferenceName(dst[0:wd] + match + dst[wd+1:])
+}
+
+func (s RefSpec) String() string {
+ return string(s)
+}
+
+// MatchAny returns true if any of the RefSpec match with the given ReferenceName.
+func MatchAny(l []RefSpec, n plumbing.ReferenceName) bool {
+ for _, r := range l {
+ if r.Match(n) {
+ return true
+ }
+ }
+
+ return false
+}