From 8ffbc4016a061015afe74fb5386c1938338dac03 Mon Sep 17 00:00:00 2001 From: Julian Phillips Date: Thu, 30 Jun 2011 18:54:53 +1000 Subject: [PATCH] goinstall: Add support for generic hosts using special import form This change extends goinstall to support "magic" package names of the form: /./ Where is the hostname, the path to the repository, the type of vcs (git, hg, bzr or svn), and is the path inside the repository that contains the source code for the package. For example: "example.com/pub/foo.hg/src" means download the Mercurial repository at either pub/foo.hg or pub/foo from example.com and then build and install the source files from src inside the repository checkout. Repositories on the built-in hostings sites (github, bitbucket, launchpad and googlecode) must still use the old form (i.e. github.com/xxx/yyy.git/src will be rejected). R=adg, rsc CC=golang-dev https://golang.org/cl/4626064 --- src/cmd/goinstall/download.go | 54 +++++++++++++++++++++++++++++------ 1 file changed, 46 insertions(+), 8 deletions(-) diff --git a/src/cmd/goinstall/download.go b/src/cmd/goinstall/download.go index 129c0459a6..957f058554 100644 --- a/src/cmd/goinstall/download.go +++ b/src/cmd/goinstall/download.go @@ -7,6 +7,7 @@ package main import ( + "exec" "http" "os" "path/filepath" @@ -34,6 +35,7 @@ func maybeReportToDashboard(path string) { type host struct { pattern *regexp.Regexp protocol string + suffix string } // a vcs represents a version control system @@ -76,9 +78,10 @@ var hg = vcs{ logReleaseFlag: "-rrelease", check: "identify", protocols: []string{"http"}, + suffix: ".hg", defaultHosts: []host{ - {regexp.MustCompile(`^([a-z0-9\-]+\.googlecode\.com/hg)(/[a-z0-9A-Z_.\-/]*)?$`), "https"}, - {regexp.MustCompile(`^(bitbucket\.org/[a-z0-9A-Z_.\-]+/[a-z0-9A-Z_.\-]+)(/[a-z0-9A-Z_.\-/]*)?$`), "http"}, + {regexp.MustCompile(`^([a-z0-9\-]+\.googlecode\.com/hg)(/[a-z0-9A-Z_.\-/]*)?$`), "https", ""}, + {regexp.MustCompile(`^(bitbucket\.org/[a-z0-9A-Z_.\-]+/[a-z0-9A-Z_.\-]+)(/[a-z0-9A-Z_.\-/]*)?$`), "http", ""}, }, } @@ -98,7 +101,7 @@ var git = vcs{ protocols: []string{"git", "http"}, suffix: ".git", defaultHosts: []host{ - {regexp.MustCompile(`^(github\.com/[a-z0-9A-Z_.\-]+/[a-z0-9A-Z_.\-]+)(/[a-z0-9A-Z_.\-/]*)?$`), "http"}, + {regexp.MustCompile(`^(github\.com/[a-z0-9A-Z_.\-]+/[a-z0-9A-Z_.\-]+)(/[a-z0-9A-Z_.\-/]*)?$`), "http", ".git"}, }, } @@ -115,8 +118,9 @@ var svn = vcs{ logReleaseFlag: "release", check: "info", protocols: []string{"http", "svn"}, + suffix: ".svn", defaultHosts: []host{ - {regexp.MustCompile(`^([a-z0-9\-]+\.googlecode\.com/svn)(/[a-z0-9A-Z_.\-/]*)?$`), "https"}, + {regexp.MustCompile(`^([a-z0-9\-]+\.googlecode\.com/svn)(/[a-z0-9A-Z_.\-/]*)?$`), "https", ""}, }, } @@ -135,13 +139,40 @@ var bzr = vcs{ logReleaseFlag: "-rrelease", check: "info", protocols: []string{"http", "bzr"}, + suffix: ".bzr", defaultHosts: []host{ - {regexp.MustCompile(`^(launchpad\.net/([a-z0-9A-Z_.\-]+(/[a-z0-9A-Z_.\-]+)?|~[a-z0-9A-Z_.\-]+/(\+junk|[a-z0-9A-Z_.\-]+)/[a-z0-9A-Z_.\-]+))(/[a-z0-9A-Z_.\-/]+)?$`), "https"}, + {regexp.MustCompile(`^(launchpad\.net/([a-z0-9A-Z_.\-]+(/[a-z0-9A-Z_.\-]+)?|~[a-z0-9A-Z_.\-]+/(\+junk|[a-z0-9A-Z_.\-]+)/[a-z0-9A-Z_.\-]+))(/[a-z0-9A-Z_.\-/]+)?$`), "https", ""}, }, } var vcsList = []*vcs{&git, &hg, &bzr, &svn} +func (v *vcs) findRepo(prefix string) *vcsMatch { + for _, proto := range v.protocols { + for _, suffix := range []string{v.suffix, ""} { + repo := proto + "://" + prefix + suffix + out, err := exec.Command(v.cmd, v.check, repo).CombinedOutput() + if err == nil { + return &vcsMatch{v, prefix + v.suffix, repo} + } + printf("find %s: %s %s %s: %v\n%s\n", prefix, v.cmd, v.check, repo, err, out) + } + } + + errorf("find %s: couldn't find %s repository\n", prefix, v.name) + return nil +} + +func findRepo(pkg string) *vcsMatch { + for _, v := range vcsList { + i := strings.Index(pkg+"/", v.suffix+"/") + if i >= 0 { + return v.findRepo(pkg[:i]) + } + } + return nil +} + // isRemote returns true if the first part of the package name looks like a // hostname - i.e. contains at least one '.' and the last part is at least 2 // characters. @@ -162,6 +193,7 @@ func download(pkg, srcDir string) os.Error { if strings.Contains(pkg, "..") { return os.NewError("invalid path (contains ..)") } + dashpath := pkg var m *vcsMatch for _, v := range vcsList { for _, host := range v.defaultHosts { @@ -169,15 +201,19 @@ func download(pkg, srcDir string) os.Error { if v.suffix != "" && strings.HasSuffix(hm[1], v.suffix) { return os.NewError("repository " + pkg + " should not have " + v.suffix + " suffix") } - repo := host.protocol + "://" + hm[1] + v.suffix + repo := host.protocol + "://" + hm[1] + host.suffix m = &vcsMatch{v, hm[1], repo} } } } + if m == nil { + m = findRepo(pkg) + dashpath = "" // don't report to dashboard + } if m == nil { return os.NewError("cannot download: " + pkg) } - return vcsCheckout(m.vcs, srcDir, m.prefix, m.repo, pkg) + return vcsCheckout(m.vcs, srcDir, m.prefix, m.repo, dashpath) } // Try to detect if a "release" tag exists. If it does, update @@ -219,7 +255,9 @@ func vcsCheckout(vcs *vcs, srcDir, pkgprefix, repo, dashpath string) os.Error { return err } // success on first installation - report - maybeReportToDashboard(dashpath) + if dashpath != "" { + maybeReportToDashboard(dashpath) + } } else if *update { // Retrieve new revisions from the remote branch, if the VCS // supports this operation independently (e.g. svn doesn't) -- 2.50.0