diff options
author | Julian Phillips <julian@quantumfyre.co.uk> | 2011-06-30 18:54:53 +1000 |
---|---|---|
committer | Andrew Gerrand <adg@golang.org> | 2011-06-30 18:54:53 +1000 |
commit | 8ffbc4016a061015afe74fb5386c1938338dac03 (patch) | |
tree | 97524fe99a436e4d3933a213d85c7382e4e3d516 | |
parent | 369418d29c00e96af3033afba6c3a49eb5d06175 (diff) | |
download | go-8ffbc4016a061015afe74fb5386c1938338dac03.tar.gz go-8ffbc4016a061015afe74fb5386c1938338dac03.zip |
goinstall: Add support for generic hosts using special import form
This change extends goinstall to support "magic" package names of the
form:
<host>/<repo>.<vcs>/<path>
Where <host> is the hostname, <repo> the path to the repository, <vcs>
the type of vcs (git, hg, bzr or svn), and <path> 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
-rw-r--r-- | src/cmd/goinstall/download.go | 54 |
1 files 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) |