diff options
Diffstat (limited to 'clients/common/common.go')
-rw-r--r-- | clients/common/common.go | 132 |
1 files changed, 132 insertions, 0 deletions
diff --git a/clients/common/common.go b/clients/common/common.go new file mode 100644 index 0000000..3527d7c --- /dev/null +++ b/clients/common/common.go @@ -0,0 +1,132 @@ +package common + +import ( + "fmt" + "net/url" + "strings" + + "gopkg.in/sourcegraph/go-vcsurl.v1" + "gopkg.in/src-d/go-git.v2/pktline" +) + +const GitUploadPackServiceName = "git-upload-pack" + +type Endpoint string + +func NewEndpoint(url string) (Endpoint, error) { + vcs, err := vcsurl.Parse(url) + if err != nil { + return "", err + } + + link := vcs.Link() + if !strings.HasSuffix(link, ".git") { + link += ".git" + } + + return Endpoint(link), nil +} + +func (e Endpoint) Service(name string) string { + return fmt.Sprintf("%s/info/refs?service=%s", e, name) +} + +// Capabilities contains all the server capabilities +// https://github.com/git/git/blob/master/Documentation/technical/protocol-capabilities.txt +type Capabilities map[string][]string + +func parseCapabilities(line string) Capabilities { + values, _ := url.ParseQuery(strings.Replace(line, " ", "&", -1)) + + return Capabilities(values) +} + +// Supports returns true if capability is preent +func (r Capabilities) Supports(capability string) bool { + _, ok := r[capability] + return ok +} + +// Get returns the values for a capability +func (r Capabilities) Get(capability string) []string { + return r[capability] +} + +// SymbolicReference returns the reference for a given symbolic reference +func (r Capabilities) SymbolicReference(sym string) string { + if !r.Supports("symref") { + return "" + } + + for _, symref := range r.Get("symref") { + parts := strings.Split(symref, ":") + if len(parts) != 2 { + continue + } + + if parts[0] == sym { + return parts[1] + } + } + + return "" +} + +type GitUploadPackInfo struct { + Capabilities Capabilities + Branches map[string]string +} + +func NewGitUploadPackInfo(d *pktline.Decoder) (*GitUploadPackInfo, error) { + info := &GitUploadPackInfo{} + if err := info.read(d); err != nil { + return nil, err + } + + return info, nil +} + +func (r *GitUploadPackInfo) read(d *pktline.Decoder) error { + lines, err := d.ReadAll() + if err != nil { + return err + } + + r.Branches = map[string]string{} + for _, line := range lines { + if !r.isValidLine(line) { + continue + } + + if r.Capabilities == nil { + r.Capabilities = parseCapabilities(line) + continue + } + + r.readLine(line) + } + + return nil +} + +func (r *GitUploadPackInfo) isValidLine(line string) bool { + if line[0] == '#' { + return false + } + + return true +} + +func (r *GitUploadPackInfo) readLine(line string) { + commit, branch := r.getCommitAndBranch(line) + r.Branches[branch] = commit +} + +func (r *GitUploadPackInfo) getCommitAndBranch(line string) (string, string) { + parts := strings.Split(strings.Trim(line, " \n"), " ") + if len(parts) != 2 { + return "", "" + } + + return parts[0], parts[1] +} |