Browse Source

Huge imporve download repos on google code

pull/103/head
Unknown 12 years ago
parent
commit
0d6a6222e5
  1. 8
      doc/bitbucket.go
  2. 22
      doc/error.go
  3. 4
      doc/github.go
  4. 187
      doc/google.go
  5. 102
      doc/http.go
  6. 10
      doc/launchpad.go
  7. 4
      doc/oschina.go
  8. 135
      doc/vcs.go
  9. 2
      gopm.go

8
doc/bitbucket.go

@ -25,6 +25,8 @@ import (
"path"
"regexp"
"strings"
"github.com/Unknwon/com"
)
var (
@ -41,7 +43,7 @@ func getBitbucketDoc(client *http.Client, match map[string]string, installRepoPa
var repo struct {
Scm string
}
if err := httpGetJSON(client, expand("https://api.bitbucket.org/1.0/repositories/{owner}/{repo}", match), &repo); err != nil {
if err := com.HttpGetJSON(client, expand("https://api.bitbucket.org/1.0/repositories/{owner}/{repo}", match), &repo); err != nil {
return nil, err
}
match["vcs"] = repo.Scm
@ -62,7 +64,7 @@ func getBitbucketDoc(client *http.Client, match map[string]string, installRepoPa
var nodes map[string]struct {
Node string
}
if err := httpGetJSON(client, expand("https://api.bitbucket.org/1.0/repositories/{owner}/{repo}/{0}", match, nodeType), &nodes); err != nil {
if err := com.HttpGetJSON(client, expand("https://api.bitbucket.org/1.0/repositories/{owner}/{repo}/{0}", match, nodeType), &nodes); err != nil {
return nil, err
}
for t, n := range nodes {
@ -94,7 +96,7 @@ func getBitbucketDoc(client *http.Client, match map[string]string, installRepoPa
// tarball : https://bitbucket.org/{owner}/{repo}/get/{commit}.tar.gz
// Downlaod archive.
p, err := HttpGetBytes(client, expand("https://bitbucket.org/{owner}/{repo}/get/{commit}.tar.gz", match), nil)
p, err := com.HttpGetBytes(client, expand("https://bitbucket.org/{owner}/{repo}/get/{commit}.tar.gz", match), nil)
if err != nil {
return nil, err
}

22
doc/error.go

@ -23,25 +23,3 @@ var (
errNoMatch = errors.New("no match")
errUpdateTimeout = errors.New("update timeout")
)
type NotFoundError struct {
Message string
}
func (e NotFoundError) Error() string {
return e.Message
}
func isNotFound(err error) bool {
_, ok := err.(NotFoundError)
return ok
}
type RemoteError struct {
Host string
err error
}
func (e *RemoteError) Error() string {
return e.err.Error()
}

4
doc/github.go

@ -24,6 +24,8 @@ import (
"path"
"regexp"
"strings"
"github.com/Unknwon/com"
)
var (
@ -65,7 +67,7 @@ func getGithubDoc(client *http.Client, match map[string]string, installRepoPath
// tarball: https://github.com/{owner}/{repo}/tarball/{sha}
// Downlaod archive.
p, err := HttpGetBytes(client, expand("https://github.com/{owner}/{repo}/archive/{sha}.zip", match), nil)
p, err := com.HttpGetBytes(client, expand("https://github.com/{owner}/{repo}/archive/{sha}.zip", match), nil)
if err != nil {
return nil, errors.New("Fail to donwload Github repo -> " + err.Error())
}

187
doc/google.go

@ -19,58 +19,20 @@ import (
"os"
"path"
"regexp"
"strings"
"github.com/Unknwon/com"
"github.com/Unknwon/ctw/packer"
)
var (
googleRepoRe = regexp.MustCompile(`id="checkoutcmd">(hg|git|svn)`)
googleRevisionRe = regexp.MustCompile(`<h2>(?:[^ ]+ - )?Revision *([^:]+):`)
googleEtagRe = regexp.MustCompile(`^(hg|git|svn)-`)
googleFileRe = regexp.MustCompile(`<li><a href="([^"/]+)"`)
googleDirRe = regexp.MustCompile(`<li><a href="([^".]+)"`)
googlePattern = regexp.MustCompile(`^code\.google\.com/p/(?P<repo>[a-z0-9\-]+)(:?\.(?P<subrepo>[a-z0-9\-]+))?(?P<dir>/[a-z0-9A-Z_.\-/]+)?$`)
googlePattern = regexp.MustCompile(`^code\.google\.com/p/(?P<repo>[a-z0-9\-]+)(:?\.(?P<subrepo>[a-z0-9\-]+))?(?P<dir>/[a-z0-9A-Z_.\-/]+)?$`)
)
func setupGoogleMatch(match map[string]string) {
if s := match["subrepo"]; s != "" {
match["dot"] = "."
match["query"] = "?repo=" + s
} else {
match["dot"] = ""
match["query"] = ""
}
}
func getGoogleVCS(client *http.Client, match map[string]string) error {
// Scrape the HTML project page to find the VCS.
p, err := HttpGetBytes(client, expand("http://code.google.com/p/{repo}/source/checkout", match), nil)
if err != nil {
return err
}
m := googleRepoRe.FindSubmatch(p)
if m == nil {
return NotFoundError{"Could not VCS on Google Code project page."}
}
match["vcs"] = string(m[1])
return nil
}
// getGoogleDoc downloads raw files from code.google.com.
func getGoogleDoc(client *http.Client, match map[string]string, installRepoPath string, nod *Node, cmdFlags map[string]bool) ([]string, error) {
setupGoogleMatch(match)
packer.SetupGoogleMatch(match)
// Check version control.
if m := googleEtagRe.FindStringSubmatch(nod.Value); m != nil {
match["vcs"] = m[1]
} else if err := getGoogleVCS(client, match); err != nil {
return nil, err
}
rootPath := expand("http://{subrepo}{dot}{repo}.googlecode.com/{vcs}{dir}/", match)
// Scrape the repo browser to find the project revision and individual Go files.
p, err := HttpGetBytes(client, rootPath+"?r="+nod.Value, nil)
if err != nil {
if err := packer.GetGoogleVCS(client, match); err != nil {
return nil, err
}
@ -89,143 +51,24 @@ func getGoogleDoc(client *http.Client, match map[string]string, installRepoPath
// Remove old files.
os.RemoveAll(installPath + "/")
os.MkdirAll(installPath+"/", os.ModePerm)
// Get source files in root path.
files := make([]*source, 0, 5)
for _, m := range googleFileRe.FindAllSubmatch(p, -1) {
fname := strings.Split(string(m[1]), "?")[0]
if strings.HasPrefix(fname, ".") {
continue
}
files = append(files, &source{
name: fname,
rawURL: expand("http://{subrepo}{dot}{repo}.googlecode.com/{vcs}{dir}/{0}", match, fname) + "?r=" + nod.Value,
})
}
// Fetch files from VCS.
if err := fetchFiles(client, files, nil); err != nil {
match["tag"] = nod.Value
err := packer.PackToFile(match["importPath"], installPath+".zip", match)
if err != nil {
return nil, err
}
// Save files.
for _, f := range files {
absPath := installPath + "/"
// Create diretory before create file.
os.MkdirAll(path.Dir(absPath), os.ModePerm)
// Write data to file
fw, err := os.Create(absPath + f.name)
if err != nil {
return nil, err
}
_, err = fw.Write(f.data)
fw.Close()
if err != nil {
return nil, err
}
}
dirs := make([]string, 0, 3)
// Get subdirectories.
for _, m := range googleDirRe.FindAllSubmatch(p, -1) {
dirName := strings.Split(string(m[1]), "?")[0]
if strings.HasSuffix(dirName, "/") {
dirs = append(dirs, dirName)
}
}
err = downloadFiles(client, match, rootPath, installPath+"/", nod.Value, dirs)
dirs, err := com.Unzip(installPath+".zip", path.Dir(installPath))
if err != nil {
return nil, err
}
var imports []string
os.Remove(installPath + ".zip")
os.Rename(path.Dir(installPath)+"/"+dirs[0], installPath)
// Check if need to check imports.
if nod.IsGetDeps {
dirs, err := GetDirsInfo(installPath + "/")
if err != nil {
return nil, err
}
for _, d := range dirs {
if d.IsDir() && !(!cmdFlags["-e"] && strings.Contains(d.Name(), "example")) {
absPath := installPath + "/" + d.Name() + "/"
importPkgs, err := CheckImports(absPath, match["importPath"])
if err != nil {
return nil, err
}
imports = append(imports, importPkgs...)
}
}
imports := getImports(installPath+"/", match, cmdFlags)
return imports, err
}
return imports, err
}
func downloadFiles(client *http.Client, match map[string]string, rootPath, installPath, commit string, dirs []string) error {
for _, d := range dirs {
p, err := HttpGetBytes(client, rootPath+d+"?r="+commit, nil)
if err != nil {
return err
}
// Create destination directory.
os.MkdirAll(installPath+d, os.ModePerm)
// Get source files in current path.
files := make([]*source, 0, 5)
for _, m := range googleFileRe.FindAllSubmatch(p, -1) {
fname := strings.Split(string(m[1]), "?")[0]
files = append(files, &source{
name: fname,
rawURL: expand("http://{subrepo}{dot}{repo}.googlecode.com/{vcs}{dir}/", match) + d + fname + "?r=" + commit,
})
}
// Fetch files from VCS.
if err := fetchFiles(client, files, nil); err != nil {
return err
}
// Save files.
for _, f := range files {
absPath := installPath + d
// Create diretory before create file.
os.MkdirAll(path.Dir(absPath), os.ModePerm)
// Write data to file
fw, err := os.Create(absPath + f.name)
if err != nil {
return err
}
_, err = fw.Write(f.data)
fw.Close()
if err != nil {
return err
}
}
subdirs := make([]string, 0, 3)
// Get subdirectories.
for _, m := range googleDirRe.FindAllSubmatch(p, -1) {
dirName := strings.Split(string(m[1]), "?")[0]
if strings.HasSuffix(dirName, "/") {
subdirs = append(subdirs, d+dirName)
}
}
err = downloadFiles(client, match, rootPath, installPath, commit, subdirs)
if err != nil {
return err
}
}
return nil
return nil, err
}

102
doc/http.go

@ -15,20 +15,14 @@
package doc
import (
"encoding/json"
"flag"
"fmt"
"io"
"io/ioutil"
"net"
"net/http"
"time"
"github.com/astaxie/beego"
"github.com/Unknwon/com"
)
var userAgent = "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/29.0.1541.0 Safari/537.36"
var (
dialTimeout = flag.Duration("dial_timeout", 10*time.Second, "Timeout for dialing an HTTP connection.")
requestTimeout = flag.Duration("request_timeout", 20*time.Second, "Time out for roundtripping an HTTP request.")
@ -45,7 +39,7 @@ type transport struct {
func (t *transport) RoundTrip(req *http.Request) (*http.Response, error) {
timer := time.AfterFunc(*requestTimeout, func() {
t.t.CancelRequest(req)
beego.Warn("Canceled request for %s", req.URL)
com.ColorLog("[WARN] Canceled request for %s, please interrupt the program.\n", req.URL)
})
defer timer.Stop()
resp, err := t.t.RoundTrip(req)
@ -56,95 +50,3 @@ var (
httpTransport = &transport{t: http.Transport{Dial: timeoutDial, ResponseHeaderTimeout: *requestTimeout / 2}}
HttpClient = &http.Client{Transport: httpTransport}
)
// httpGet gets the specified resource. ErrNotFound is returned if the server
// responds with status 404.
func HttpGetBytes(client *http.Client, url string, header http.Header) ([]byte, error) {
rc, err := httpGet(client, url, header)
if err != nil {
return nil, err
}
p, err := ioutil.ReadAll(rc)
rc.Close()
return p, err
}
// httpGet gets the specified resource. ErrNotFound is returned if the
// server responds with status 404.
func httpGet(client *http.Client, url string, header http.Header) (io.ReadCloser, error) {
req, err := http.NewRequest("GET", url, nil)
if err != nil {
return nil, err
}
req.Header.Set("User-Agent", userAgent)
for k, vs := range header {
req.Header[k] = vs
}
resp, err := client.Do(req)
if err != nil {
return nil, &RemoteError{req.URL.Host, err}
}
if resp.StatusCode == 200 {
return resp.Body, nil
}
resp.Body.Close()
if resp.StatusCode == 404 { // 403 can be rate limit error. || resp.StatusCode == 403 {
err = NotFoundError{"Resource not found: " + url}
} else {
err = &RemoteError{req.URL.Host, fmt.Errorf("get %s -> %d", url, resp.StatusCode)}
}
return nil, err
}
// fetchFiles fetches the source files specified by the rawURL field in parallel.
func fetchFiles(client *http.Client, files []*source, header http.Header) error {
ch := make(chan error, len(files))
for i := range files {
go func(i int) {
req, err := http.NewRequest("GET", files[i].rawURL, nil)
if err != nil {
ch <- err
return
}
req.Header.Set("User-Agent", userAgent)
for k, vs := range header {
req.Header[k] = vs
}
resp, err := client.Do(req)
if err != nil {
ch <- &RemoteError{req.URL.Host, err}
return
}
defer resp.Body.Close()
if resp.StatusCode != 200 {
ch <- &RemoteError{req.URL.Host, fmt.Errorf("get %s -> %d", req.URL, resp.StatusCode)}
return
}
files[i].data, err = ioutil.ReadAll(resp.Body)
if err != nil {
ch <- &RemoteError{req.URL.Host, err}
return
}
ch <- nil
}(i)
}
for _ = range files {
if err := <-ch; err != nil {
return err
}
}
return nil
}
func httpGetJSON(client *http.Client, url string, v interface{}) error {
rc, err := httpGet(client, url, nil)
if err != nil {
return err
}
defer rc.Close()
err = json.NewDecoder(rc).Decode(v)
if _, ok := err.(*json.SyntaxError); ok {
err = NotFoundError{"JSON syntax error at " + url}
}
return err
}

10
doc/launchpad.go

@ -21,9 +21,10 @@ import (
"io"
"net/http"
"os"
//"path"
"regexp"
"strings"
"github.com/Unknwon/com"
)
var launchpadPattern = regexp.MustCompile(`^launchpad\.net/(?P<repo>(?P<project>[a-z0-9A-Z_.\-]+)(?P<series>/[a-z0-9A-Z_.\-]+)?|~[a-z0-9A-Z_.\-]+/(\+junk|[a-z0-9A-Z_.\-]+)/[a-z0-9A-Z_.\-]+)(?P<dir>/[a-z0-9A-Z_.\-/]+)*$`)
@ -32,12 +33,13 @@ var launchpadPattern = regexp.MustCompile(`^launchpad\.net/(?P<repo>(?P<project>
func getLaunchpadDoc(client *http.Client, match map[string]string, installRepoPath string, nod *Node, cmdFlags map[string]bool) ([]string, error) {
if match["project"] != "" && match["series"] != "" {
rc, err := httpGet(client, expand("https://code.launchpad.net/{project}{series}/.bzr/branch-format", match), nil)
rc, err := com.HttpGet(client, expand("https://code.launchpad.net/{project}{series}/.bzr/branch-format", match), nil)
_, isNotFound := err.(com.NotFoundError)
switch {
case err == nil:
rc.Close()
// The structure of the import path is launchpad.net/{root}/{dir}.
case isNotFound(err):
case isNotFound:
// The structure of the import path is is launchpad.net/{project}/{dir}.
match["repo"] = match["project"]
match["dir"] = expand("{series}{dir}", match)
@ -55,7 +57,7 @@ func getLaunchpadDoc(client *http.Client, match map[string]string, installRepoPa
}
// Scrape the repo browser to find the project revision and individual Go files.
p, err := HttpGetBytes(client, downloadPath, nil)
p, err := com.HttpGetBytes(client, downloadPath, nil)
if err != nil {
return nil, err
}

4
doc/oschina.go

@ -23,6 +23,8 @@ import (
"os"
"regexp"
"strings"
"github.com/Unknwon/com"
)
var (
@ -49,7 +51,7 @@ func getOSCDoc(client *http.Client, match map[string]string, installRepoPath str
// zip: http://{projectRoot}/repository/archive?ref={sha}
// Downlaod archive.
p, err := HttpGetBytes(client, expand("http://git.oschina.net/{owner}/{repo}/repository/archive?ref={sha}", match), nil)
p, err := com.HttpGetBytes(client, expand("http://git.oschina.net/{owner}/{repo}/repository/archive?ref={sha}", match), nil)
if err != nil {
return nil, errors.New("Fail to donwload OSChina repo -> " + err.Error())
}

135
doc/vcs.go

@ -28,6 +28,8 @@ import (
"regexp"
"strconv"
"strings"
"github.com/Unknwon/com"
)
var (
@ -112,7 +114,7 @@ func downloadGit(schemes []string, repo, savedEtag string) (string, string, erro
}
if scheme == "" {
return "", "", NotFoundError{"VCS not found"}
return "", "", com.NotFoundError{"VCS not found"}
}
tags := make(map[string]string)
@ -172,7 +174,7 @@ func bestTag(tags map[string]string, defaultTag string) (string, string, error)
if commit, ok := tags[defaultTag]; ok {
return defaultTag, commit, nil
}
return "", "", NotFoundError{"Tag or branch not found."}
return "", "", com.NotFoundError{"Tag or branch not found."}
}
// expand replaces {k} in template with match[k] or subs[atoi(k)] if k is not in match.
@ -199,56 +201,6 @@ func expand(template string, match map[string]string, subs ...string) string {
return string(p)
}
// checkImports checks package denpendencies.
func CheckImports(absPath, importPath string) (importPkgs []string, err error) {
dir, err := os.Open(absPath)
if err != nil {
return nil, err
}
defer dir.Close()
// Get file info slice.
fis, err := dir.Readdir(0)
if err != nil {
return nil, err
}
files := make([]*source, 0, 10)
for _, fi := range fis {
// Only handle files.
if strings.HasSuffix(fi.Name(), ".go") {
f, err := os.Open(absPath + fi.Name())
if err != nil {
return nil, err
}
fbytes := make([]byte, fi.Size())
_, err = f.Read(fbytes)
f.Close()
if err != nil {
return nil, err
}
files = append(files, &source{
name: fi.Name(),
data: fbytes,
})
}
}
// Check if has Go source files.
if len(files) > 0 {
w := &walker{ImportPath: importPath}
importPkgs, err = w.build(files)
if err != nil {
return nil, err
}
}
return importPkgs, err
}
// PureDownload downloads package without version control.
func PureDownload(nod *Node, installRepoPath string, flags map[string]bool) ([]string, error) {
for _, s := range services {
@ -287,7 +239,7 @@ func getDynamic(client *http.Client, nod *Node, installRepoPath string, flags ma
return nil, err
}
if rootMatch["projectRoot"] != match["projectRoot"] {
return nil, NotFoundError{"Project root mismatch."}
return nil, com.NotFoundError{"Project root mismatch."}
}
}
@ -312,7 +264,7 @@ func fetchMeta(client *http.Client, importPath string) (map[string]string, error
scheme = "http"
resp, err = client.Get(scheme + "://" + uri)
if err != nil {
return nil, &RemoteError{strings.SplitN(importPath, "/", 2)[0], err}
return nil, &com.RemoteError{strings.SplitN(importPath, "/", 2)[0], err}
}
}
defer resp.Body.Close()
@ -359,7 +311,7 @@ metaScan:
continue metaScan
}
if match != nil {
return nil, NotFoundError{"More than one <meta> found at " + scheme + "://" + importPath}
return nil, com.NotFoundError{"More than one <meta> found at " + scheme + "://" + importPath}
}
projectRoot, vcs, repo := f[0], f[1], f[2]
@ -367,7 +319,7 @@ metaScan:
repo = strings.TrimSuffix(repo, "."+vcs)
i := strings.Index(repo, "://")
if i < 0 {
return nil, NotFoundError{"Bad repo URL in <meta>."}
return nil, com.NotFoundError{"Bad repo URL in <meta>."}
}
proto := repo[:i]
repo = repo[i+len("://"):]
@ -390,7 +342,76 @@ metaScan:
}
}
if match == nil {
return nil, NotFoundError{"<meta> not found."}
return nil, com.NotFoundError{"<meta> not found."}
}
return match, nil
}
func getImports(rootPath string, match map[string]string, cmdFlags map[string]bool) (imports []string) {
dirs, err := GetDirsInfo(rootPath)
if err != nil {
return nil
}
for _, d := range dirs {
if d.IsDir() && !(!cmdFlags["-e"] && strings.Contains(d.Name(), "example")) {
absPath := rootPath + d.Name() + "/"
importPkgs, err := CheckImports(absPath, match["importPath"])
if err != nil {
return nil
}
imports = append(imports, importPkgs...)
}
}
return imports
}
// checkImports checks package denpendencies.
func CheckImports(absPath, importPath string) (importPkgs []string, err error) {
dir, err := os.Open(absPath)
if err != nil {
return nil, err
}
defer dir.Close()
// Get file info slice.
fis, err := dir.Readdir(0)
if err != nil {
return nil, err
}
files := make([]*source, 0, 10)
for _, fi := range fis {
// Only handle files.
if strings.HasSuffix(fi.Name(), ".go") {
f, err := os.Open(absPath + fi.Name())
if err != nil {
return nil, err
}
fbytes := make([]byte, fi.Size())
_, err = f.Read(fbytes)
f.Close()
if err != nil {
return nil, err
}
files = append(files, &source{
name: fi.Name(),
data: fbytes,
})
}
}
// Check if has Go source files.
if len(files) > 0 {
w := &walker{ImportPath: importPath}
importPkgs, err = w.build(files)
if err != nil {
return nil, err
}
}
return importPkgs, err
}

2
gopm.go

@ -37,7 +37,7 @@ import (
// Test that go1.1 tag above is included in builds. main.go refers to this definition.
const go11tag = true
const APP_VER = "0.2.2.0819"
const APP_VER = "0.2.5.0827"
var (
config map[string]interface{}

Loading…
Cancel
Save