Платформа ЦРНП "Мирокод" для разработки проектов
https://git.mirocod.ru
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
209 lines
4.9 KiB
209 lines
4.9 KiB
package plumbing |
|
|
|
import ( |
|
"errors" |
|
"fmt" |
|
"strings" |
|
) |
|
|
|
const ( |
|
refPrefix = "refs/" |
|
refHeadPrefix = refPrefix + "heads/" |
|
refTagPrefix = refPrefix + "tags/" |
|
refRemotePrefix = refPrefix + "remotes/" |
|
refNotePrefix = refPrefix + "notes/" |
|
symrefPrefix = "ref: " |
|
) |
|
|
|
// RefRevParseRules are a set of rules to parse references into short names. |
|
// These are the same rules as used by git in shorten_unambiguous_ref. |
|
// See: https://github.com/git/git/blob/e0aaa1b6532cfce93d87af9bc813fb2e7a7ce9d7/refs.c#L417 |
|
var RefRevParseRules = []string{ |
|
"refs/%s", |
|
"refs/tags/%s", |
|
"refs/heads/%s", |
|
"refs/remotes/%s", |
|
"refs/remotes/%s/HEAD", |
|
} |
|
|
|
var ( |
|
ErrReferenceNotFound = errors.New("reference not found") |
|
) |
|
|
|
// ReferenceType reference type's |
|
type ReferenceType int8 |
|
|
|
const ( |
|
InvalidReference ReferenceType = 0 |
|
HashReference ReferenceType = 1 |
|
SymbolicReference ReferenceType = 2 |
|
) |
|
|
|
func (r ReferenceType) String() string { |
|
switch r { |
|
case InvalidReference: |
|
return "invalid-reference" |
|
case HashReference: |
|
return "hash-reference" |
|
case SymbolicReference: |
|
return "symbolic-reference" |
|
} |
|
|
|
return "" |
|
} |
|
|
|
// ReferenceName reference name's |
|
type ReferenceName string |
|
|
|
// NewBranchReferenceName returns a reference name describing a branch based on |
|
// his short name. |
|
func NewBranchReferenceName(name string) ReferenceName { |
|
return ReferenceName(refHeadPrefix + name) |
|
} |
|
|
|
// NewNoteReferenceName returns a reference name describing a note based on his |
|
// short name. |
|
func NewNoteReferenceName(name string) ReferenceName { |
|
return ReferenceName(refNotePrefix + name) |
|
} |
|
|
|
// NewRemoteReferenceName returns a reference name describing a remote branch |
|
// based on his short name and the remote name. |
|
func NewRemoteReferenceName(remote, name string) ReferenceName { |
|
return ReferenceName(refRemotePrefix + fmt.Sprintf("%s/%s", remote, name)) |
|
} |
|
|
|
// NewRemoteHEADReferenceName returns a reference name describing a the HEAD |
|
// branch of a remote. |
|
func NewRemoteHEADReferenceName(remote string) ReferenceName { |
|
return ReferenceName(refRemotePrefix + fmt.Sprintf("%s/%s", remote, HEAD)) |
|
} |
|
|
|
// NewTagReferenceName returns a reference name describing a tag based on short |
|
// his name. |
|
func NewTagReferenceName(name string) ReferenceName { |
|
return ReferenceName(refTagPrefix + name) |
|
} |
|
|
|
// IsBranch check if a reference is a branch |
|
func (r ReferenceName) IsBranch() bool { |
|
return strings.HasPrefix(string(r), refHeadPrefix) |
|
} |
|
|
|
// IsNote check if a reference is a note |
|
func (r ReferenceName) IsNote() bool { |
|
return strings.HasPrefix(string(r), refNotePrefix) |
|
} |
|
|
|
// IsRemote check if a reference is a remote |
|
func (r ReferenceName) IsRemote() bool { |
|
return strings.HasPrefix(string(r), refRemotePrefix) |
|
} |
|
|
|
// IsTag check if a reference is a tag |
|
func (r ReferenceName) IsTag() bool { |
|
return strings.HasPrefix(string(r), refTagPrefix) |
|
} |
|
|
|
func (r ReferenceName) String() string { |
|
return string(r) |
|
} |
|
|
|
// Short returns the short name of a ReferenceName |
|
func (r ReferenceName) Short() string { |
|
s := string(r) |
|
res := s |
|
for _, format := range RefRevParseRules { |
|
_, err := fmt.Sscanf(s, format, &res) |
|
if err == nil { |
|
continue |
|
} |
|
} |
|
|
|
return res |
|
} |
|
|
|
const ( |
|
HEAD ReferenceName = "HEAD" |
|
Master ReferenceName = "refs/heads/master" |
|
) |
|
|
|
// Reference is a representation of git reference |
|
type Reference struct { |
|
t ReferenceType |
|
n ReferenceName |
|
h Hash |
|
target ReferenceName |
|
} |
|
|
|
// NewReferenceFromStrings creates a reference from name and target as string, |
|
// the resulting reference can be a SymbolicReference or a HashReference base |
|
// on the target provided |
|
func NewReferenceFromStrings(name, target string) *Reference { |
|
n := ReferenceName(name) |
|
|
|
if strings.HasPrefix(target, symrefPrefix) { |
|
target := ReferenceName(target[len(symrefPrefix):]) |
|
return NewSymbolicReference(n, target) |
|
} |
|
|
|
return NewHashReference(n, NewHash(target)) |
|
} |
|
|
|
// NewSymbolicReference creates a new SymbolicReference reference |
|
func NewSymbolicReference(n, target ReferenceName) *Reference { |
|
return &Reference{ |
|
t: SymbolicReference, |
|
n: n, |
|
target: target, |
|
} |
|
} |
|
|
|
// NewHashReference creates a new HashReference reference |
|
func NewHashReference(n ReferenceName, h Hash) *Reference { |
|
return &Reference{ |
|
t: HashReference, |
|
n: n, |
|
h: h, |
|
} |
|
} |
|
|
|
// Type return the type of a reference |
|
func (r *Reference) Type() ReferenceType { |
|
return r.t |
|
} |
|
|
|
// Name return the name of a reference |
|
func (r *Reference) Name() ReferenceName { |
|
return r.n |
|
} |
|
|
|
// Hash return the hash of a hash reference |
|
func (r *Reference) Hash() Hash { |
|
return r.h |
|
} |
|
|
|
// Target return the target of a symbolic reference |
|
func (r *Reference) Target() ReferenceName { |
|
return r.target |
|
} |
|
|
|
// Strings dump a reference as a [2]string |
|
func (r *Reference) Strings() [2]string { |
|
var o [2]string |
|
o[0] = r.Name().String() |
|
|
|
switch r.Type() { |
|
case HashReference: |
|
o[1] = r.Hash().String() |
|
case SymbolicReference: |
|
o[1] = symrefPrefix + r.Target().String() |
|
} |
|
|
|
return o |
|
} |
|
|
|
func (r *Reference) String() string { |
|
s := r.Strings() |
|
return fmt.Sprintf("%s %s", s[1], s[0]) |
|
}
|
|
|