aboutsummaryrefslogtreecommitdiffstats
path: root/clients/common/common.go
diff options
context:
space:
mode:
Diffstat (limited to 'clients/common/common.go')
-rw-r--r--clients/common/common.go132
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]
+}