aboutsummaryrefslogtreecommitdiffstats
path: root/clients/common
diff options
context:
space:
mode:
Diffstat (limited to 'clients/common')
-rw-r--r--clients/common/common.go132
-rw-r--r--clients/common/common_test.go37
2 files changed, 169 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]
+}
diff --git a/clients/common/common_test.go b/clients/common/common_test.go
new file mode 100644
index 0000000..0b9b60a
--- /dev/null
+++ b/clients/common/common_test.go
@@ -0,0 +1,37 @@
+package common
+
+import (
+ "testing"
+
+ . "gopkg.in/check.v1"
+)
+
+func Test(t *testing.T) { TestingT(t) }
+
+type SuiteCommon struct{}
+
+var _ = Suite(&SuiteCommon{})
+
+func (s *SuiteCommon) TestNewEndpoint(c *C) {
+ e, err := NewEndpoint("git@github.com:user/repository.git")
+ c.Assert(err, IsNil)
+ c.Assert(e, Equals, Endpoint("https://github.com/user/repository.git"))
+}
+
+func (s *SuiteCommon) TestNewEndpointWrongForgat(c *C) {
+ e, err := NewEndpoint("foo")
+ c.Assert(err, Not(IsNil))
+ c.Assert(e, Equals, Endpoint(""))
+}
+
+func (s *SuiteCommon) TestEndpointService(c *C) {
+ e, _ := NewEndpoint("git@github.com:user/repository.git")
+ c.Assert(e.Service("foo"), Equals, "https://github.com/user/repository.git/info/refs?service=foo")
+}
+
+const CapabilitiesFixture = "6ecf0ef2c2dffb796033e5a02219af86ec6584e5 HEADmulti_ack thin-pack side-band side-band-64k ofs-delta shallow no-progress include-tag multi_ack_detailed no-done symref=HEAD:refs/heads/master agent=git/2:2.4.8~dbussink-fix-enterprise-tokens-compilation-1167-gc7006cf"
+
+func (s *SuiteCommon) TestCapabilitiesSymbolicReference(c *C) {
+ cap := parseCapabilities(CapabilitiesFixture)
+ c.Assert(cap.SymbolicReference("HEAD"), Equals, "refs/heads/master")
+}