summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGustavo Niemeyer <gustavo@niemeyer.net>2010-06-30 23:33:49 -0700
committerGustavo Niemeyer <gustavo@niemeyer.net>2010-06-30 23:33:49 -0700
commitcf7ae5a1d0bff75439e36184787ac2ed204824d8 (patch)
treef48840f40bf0dfca33280ba6a9eff5a556971cf9
parenta9290c16cab4cb1101f5fb3da36f4f9fc162502b (diff)
downloadgolang-cf7ae5a1d0bff75439e36184787ac2ed204824d8.tar.gz
goinstall: support for Bazaar+Launchpad
With these changes, goinstall is now able to use branches maintained with Bazaar located in Launchpad. Project aliases such as /project and /project/series are supported in addition to specific user or team branches such as /~user/project/branch. Temporary branches under the +junk special project are also supported. As a curious side effect, since Launchpad is able to import code from other locations, they can be indirectly accessible too if desired. R=rsc CC=golang-dev http://codereview.appspot.com/1699050 Committer: Russ Cox <rsc@golang.org>
-rw-r--r--src/cmd/goinstall/doc.go9
-rw-r--r--src/cmd/goinstall/download.go120
-rw-r--r--src/cmd/goinstall/main.go2
3 files changed, 88 insertions, 43 deletions
diff --git a/src/cmd/goinstall/doc.go b/src/cmd/goinstall/doc.go
index c5f93f929..80b30d5ac 100644
--- a/src/cmd/goinstall/doc.go
+++ b/src/cmd/goinstall/doc.go
@@ -42,6 +42,15 @@ if necessary. The recognized code hosting sites are:
import "project.googlecode.com/svn/trunk"
import "project.googlecode.com/svn/trunk/sub/directory"
+ Launchpad
+
+ import "launchpad.net/project
+ import "launchpad.net/project/series
+ import "launchpad.net/project/series/sub/directory
+
+ import "launchpad.net/~user/project/branch
+ import "launchpad.net/~user/project/branch/sub/directory
+
If the destination directory (e.g., $GOROOT/src/pkg/bitbucket.org/user/project)
already exists and contains an appropriate checkout, goinstall will not
diff --git a/src/cmd/goinstall/download.go b/src/cmd/goinstall/download.go
index d8d999d78..3422e8186 100644
--- a/src/cmd/goinstall/download.go
+++ b/src/cmd/goinstall/download.go
@@ -34,6 +34,7 @@ func maybeReportToDashboard(path string) {
var googlecode = regexp.MustCompile(`^([a-z0-9\-]+\.googlecode\.com/(svn|hg))(/[a-z0-9A-Z_.\-/]*)?$`)
var github = regexp.MustCompile(`^(github\.com/[a-z0-9A-Z_.\-]+/[a-z0-9A-Z_.\-]+)(/[a-z0-9A-Z_.\-/]*)?$`)
var bitbucket = regexp.MustCompile(`^(bitbucket\.org/[a-z0-9A-Z_.\-]+/[a-z0-9A-Z_.\-]+)(/[a-z0-9A-Z_.\-/]*)?$`)
+var launchpad = 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_.\-/]+)?$`)
// download checks out or updates pkg from the remote server.
func download(pkg string) (string, os.Error) {
@@ -71,53 +72,78 @@ func download(pkg string) (string, os.Error) {
}
return root + pkg, nil
}
+ if m := launchpad.MatchStrings(pkg); m != nil {
+ // Either lp.net/<project>[/<series>[/<path>]]
+ // or lp.net/~<user or team>/<project>/<branch>[/<path>]
+ if err := vcsCheckout(&bzr, root+m[1], "https://"+m[1], m[1]); err != nil {
+ return "", err
+ }
+ return root + pkg, nil
+ }
return "", os.ErrorString("unknown repository: " + pkg)
}
// a vcs represents a version control system
// like Mercurial, Git, or Subversion.
type vcs struct {
- cmd string
- metadir string
- clone string
- update string
- pull string
- log string
- logLimitFlag string
- logReleaseFlag string
+ cmd string
+ metadir string
+ clone string
+ update string
+ updateReleaseFlag string
+ pull string
+ pullForceFlag string
+ log string
+ logLimitFlag string
+ logReleaseFlag string
}
var hg = vcs{
- cmd: "hg",
- metadir: ".hg",
- clone: "clone",
- update: "update",
- pull: "pull",
- log: "log",
- logLimitFlag: "-l1",
- logReleaseFlag: "-rrelease",
+ cmd: "hg",
+ metadir: ".hg",
+ clone: "clone",
+ update: "update",
+ updateReleaseFlag: "release",
+ pull: "pull",
+ log: "log",
+ logLimitFlag: "-l1",
+ logReleaseFlag: "-rrelease",
}
var git = vcs{
- cmd: "git",
- metadir: ".git",
- clone: "clone",
- update: "pull",
- pull: "fetch",
- log: "log",
- logLimitFlag: "-n1",
- logReleaseFlag: "release",
+ cmd: "git",
+ metadir: ".git",
+ clone: "clone",
+ update: "pull",
+ updateReleaseFlag: "release",
+ pull: "fetch",
+ log: "log",
+ logLimitFlag: "-n1",
+ logReleaseFlag: "release",
}
var svn = vcs{
- cmd: "svn",
- metadir: ".svn",
- clone: "checkout",
- update: "update",
- pull: "",
- log: "log",
- logLimitFlag: "-l1",
- logReleaseFlag: "release",
+ cmd: "svn",
+ metadir: ".svn",
+ clone: "checkout",
+ update: "update",
+ updateReleaseFlag: "release",
+ log: "log",
+ logLimitFlag: "-l1",
+ logReleaseFlag: "release",
+}
+
+var bzr = vcs{
+ cmd: "bzr",
+ metadir: ".bzr",
+ clone: "branch",
+ update: "update",
+ updateReleaseFlag: "-rrelease",
+ pull: "pull",
+ pullForceFlag: "--overwrite",
+ log: "log",
+ logLimitFlag: "-l1",
+ logReleaseFlag: "-rrelease",
}
// vcsCheckout checks out repo into dst using vcs.
@@ -138,27 +164,37 @@ func vcsCheckout(vcs *vcs, dst, repo, dashpath string) os.Error {
if err := run("/", nil, vcs.cmd, vcs.clone, repo, dst); err != nil {
return err
}
- quietRun(dst, nil, vcs.cmd, vcs.update, "release")
+ quietRun(dst, nil, vcs.cmd, vcs.update, vcs.updateReleaseFlag)
// success on first installation - report
maybeReportToDashboard(dashpath)
} else if *update {
+ // Retrieve new revisions from the remote branch, if the VCS
+ // supports this operation independently (e.g. svn doesn't)
if vcs.pull != "" {
- if err := run(dst, nil, vcs.cmd, vcs.pull); err != nil {
+ if vcs.pullForceFlag != "" {
+ if err := run(dst, nil, vcs.cmd, vcs.pull, vcs.pullForceFlag); err != nil {
+ return err
+ }
+ } else if err := run(dst, nil, vcs.cmd, vcs.pull); err != nil {
return err
}
}
- // check for release with hg log -l 1 -r release
- // if success, hg update release
- // else hg update
+
+ // Try to detect if a "release" tag exists. If it does, update
+ // to the tagged version. If no tag is found, then update to the
+ // tip afterwards.
+ // NOTE(gustavo@niemeyer.net): What is the expected behavior with
+ // svn here? "svn log -l1 release" doesn't make sense in this
+ // context and will probably fail.
if err := quietRun(dst, nil, vcs.cmd, vcs.log, vcs.logLimitFlag, vcs.logReleaseFlag); err == nil {
- if err := run(dst, nil, vcs.cmd, vcs.update, "release"); err != nil {
- return err
- }
- } else {
- if err := run(dst, nil, vcs.cmd, vcs.update); err != nil {
+ if err := run(dst, nil, vcs.cmd, vcs.update, vcs.updateReleaseFlag); err != nil {
+ // The VCS supports tagging, has the "release" tag, but
+ // something else went wrong. Report.
return err
}
+ } else if err := run(dst, nil, vcs.cmd, vcs.update); err != nil {
+ return err
}
}
return nil
diff --git a/src/cmd/goinstall/main.go b/src/cmd/goinstall/main.go
index ecd21536e..60efdf082 100644
--- a/src/cmd/goinstall/main.go
+++ b/src/cmd/goinstall/main.go
@@ -184,7 +184,7 @@ func quietRun(dir string, stdin []byte, cmd ...string) os.Error {
return genRun(dir, stdin, cmd, true)
}
-// genRun implements run and tryRun.
+// genRun implements run and quietRun.
func genRun(dir string, stdin []byte, cmd []string, quiet bool) os.Error {
bin, err := exec.LookPath(cmd[0])
if err != nil {