Handle Google Project Hosting redirects
If the owner of a project on Google Project Hosting configured a
redirect to another service, then redirect the corresponding pages on
godoc.org.
Examples of redirected packags are:
code.google.com/p/gocc -> github.com/goccmack/gocc
code.google.com/p/vitess/go/bson -> github.com/youtube/vitess/go/bson
diff --git a/gosrc/client.go b/gosrc/client.go
index be19e0f..09d54e3 100644
--- a/gosrc/client.go
+++ b/gosrc/client.go
@@ -30,6 +30,7 @@
return &RemoteError{resp.Request.URL.Host, fmt.Errorf("%d: (%s)", resp.StatusCode, resp.Request.URL.String())}
}
+// get issues a GET to the specified URL.
func (c *httpClient) get(url string) (*http.Response, error) {
req, err := http.NewRequest("GET", url, nil)
if err != nil {
@@ -45,6 +46,26 @@
return resp, err
}
+// getNoFollow issues a GET to the specified URL without following redirects.
+func (c *httpClient) getNoFollow(url string) (*http.Response, error) {
+ req, err := http.NewRequest("GET", url, nil)
+ if err != nil {
+ return nil, err
+ }
+ for k, vs := range c.header {
+ req.Header[k] = vs
+ }
+ t := c.client.Transport
+ if t == nil {
+ t = http.DefaultTransport
+ }
+ resp, err := t.RoundTrip(req)
+ if err != nil {
+ return nil, &RemoteError{req.URL.Host, err}
+ }
+ return resp, err
+}
+
func (c *httpClient) getBytes(url string) ([]byte, error) {
resp, err := c.get(url)
if err != nil {
diff --git a/gosrc/google.go b/gosrc/google.go
index c36c223..1a47b59 100644
--- a/gosrc/google.go
+++ b/gosrc/google.go
@@ -30,10 +30,32 @@
googleFileRe = regexp.MustCompile(`<li><a href="([^"]+)"`)
)
+func checkGoogleRedir(c *httpClient, match map[string]string) error {
+ resp, err := c.getNoFollow(expand("https://code.google.com/{pr}/{repo}/", match))
+ if err != nil {
+ return err
+ }
+ defer resp.Body.Close()
+ if resp.StatusCode == http.StatusOK {
+ return nil
+ }
+ if resp.StatusCode == http.StatusMovedPermanently {
+ if u, err := url.Parse(resp.Header.Get("Location")); err == nil {
+ p := u.Host + u.Path + match["dir"]
+ return NotFoundError{Message: "Project moved", Redirect: p}
+ }
+ }
+ return c.err(resp)
+}
+
func getGoogleDir(client *http.Client, match map[string]string, savedEtag string) (*Directory, error) {
+ setupGoogleMatch(match)
c := &httpClient{client: client}
- setupGoogleMatch(match)
+ if err := checkGoogleRedir(c, match); err != nil {
+ return nil, err
+ }
+
if m := googleEtagRe.FindStringSubmatch(savedEtag); m != nil {
match["vcs"] = m[1]
} else if err := getGoogleVCS(c, match); err != nil {
diff --git a/gosrc/print.go b/gosrc/print.go
index 46de29c..f833bc3 100644
--- a/gosrc/print.go
+++ b/gosrc/print.go
@@ -44,8 +44,10 @@
gosrc.SetLocalDevMode(*local)
}
dir, err := gosrc.Get(http.DefaultClient, path, *etag)
- if err != nil {
- log.Fatal(err)
+ if e, ok := err.(gosrc.NotFoundError); ok && e.Redirect != "" {
+ log.Fatalf("redirect to %s", e.Redirect)
+ } else if err != nil {
+ log.Fatalf("%+v", err)
}
fmt.Println("ImportPath ", dir.ImportPath)