diff --git a/README.md b/README.md index 14de26766..a83c421e5 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,8 @@ gpm(Go Package Manager) is a Go package manage tool for search, install, update ## Todo -- Command `install` add support for downloading code from launchpad.net, bitbucket.org; probably, git.oschina.net, gitcafe.com, *.codeplex.com; hopefully, support user sources for downloading tarballs. +- Command `install` add support for downloading code from git.oschina.net, gitcafe.com, *.codeplex.com; +- Add support for downloading tarballs from user sources. - Command `install` installs all packages after downloaded. - After downloaded all packages in bundles or snapshots, need to check if all dependencies have been downloaded as well. - Develop user source API server template application to support user sources in bundles. diff --git a/doc/bitbucket.go b/doc/bitbucket.go index d74664660..5b9c833f5 100644 --- a/doc/bitbucket.go +++ b/doc/bitbucket.go @@ -1,17 +1,6 @@ -// Copyright 2011 Gary Burd -// Copyright 2013 Unknown -// -// Licensed under the Apache License, Version 2.0 (the "License"): you may -// not use this file except in compliance with the License. You may obtain -// a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -// License for the specific language governing permissions and limitations -// under the License. +// Copyright (c) 2013 GPMGo Members. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. package doc @@ -86,8 +75,7 @@ func GetBitbucketDoc(client *http.Client, match map[string]string, installGOPATH return nil, nil, err } - importPath := "bitbucket.org/" + expand("{owner}/{repo}", match) - installPath := installGOPATH + "/src/" + importPath + installPath := installGOPATH + "/src/" + match["importPath"] // Remove old files. os.RemoveAll(installPath + "/") @@ -116,42 +104,44 @@ func GetBitbucketDoc(client *http.Client, match map[string]string, installGOPATH fn := h.FileInfo().Name() // In case that we find directory, usually we should not. - if !strings.HasSuffix(fn, "/") { - // Check root path. - if len(autoPath) == 0 { - autoPath = fn[:strings.Index(fn, "/")] - } - absPath := strings.Replace(fn, autoPath, installPath, 1) + if strings.HasSuffix(fn, "/") { + continue + } - // Create diretory before create file. - dir := path.Dir(absPath) - if !checkDir(dir, dirs) { - dirs = append(dirs, dir) - os.MkdirAll(dir+"/", os.ModePerm) - } + // Check root path. + if len(autoPath) == 0 { + autoPath = fn[:strings.Index(fn, "/")] + } + absPath := strings.Replace(fn, autoPath, installPath, 1) - // Get data from archive. - fbytes := make([]byte, h.Size) - if _, err := io.ReadFull(tr, fbytes); err != nil { - return nil, nil, err - } + // Create diretory before create file. + dir := path.Dir(absPath) + if !checkDir(dir, dirs) && !(!cmdFlags["-e"] && strings.Contains(absPath, "example")) { + dirs = append(dirs, dir) + os.MkdirAll(dir+"/", os.ModePerm) + } - // Write data to file - fw, err := os.Create(absPath) - if err != nil { - return nil, nil, err - } + // Get data from archive. + fbytes := make([]byte, h.Size) + if _, err := io.ReadFull(tr, fbytes); err != nil { + return nil, nil, err + } - _, err = fw.Write(fbytes) - fw.Close() - if err != nil { - return nil, nil, err - } + // Write data to file + fw, err := os.Create(absPath) + if err != nil { + return nil, nil, err + } + + _, err = fw.Write(fbytes) + fw.Close() + if err != nil { + return nil, nil, err } } pkg := &Package{ - ImportPath: importPath, + ImportPath: match["importPath"], AbsPath: installPath, Commit: commit, } @@ -160,24 +150,10 @@ func GetBitbucketDoc(client *http.Client, match map[string]string, installGOPATH // Check if need to check imports. if isCheckImport { - rootdir, err := os.Open(installPath + "/") - if err != nil { - return nil, nil, err - } - defer rootdir.Close() - - dirs, err := rootdir.Readdir(0) - if err != nil { - return nil, nil, err - } - for _, d := range dirs { - if d.IsDir() { - absPath := installPath + "/" + d.Name() + "/" - imports, err = checkImports(absPath, importPath) - if err != nil { - return nil, nil, err - } + imports, err = checkImports(d+"/", match["importPath"]) + if err != nil { + return nil, nil, err } } } diff --git a/doc/github.go b/doc/github.go index 66da664a3..900980422 100644 --- a/doc/github.go +++ b/doc/github.go @@ -87,8 +87,7 @@ func GetGithubDoc(client *http.Client, match map[string]string, installGOPATH, c } shaName := expand("{repo}-{sha}", match) - importPath := "github.com/" + expand("{owner}/{repo}", match) - installPath := installGOPATH + "/src/" + importPath + installPath := installGOPATH + "/src/" + match["importPath"] // Remove old files. os.RemoveAll(installPath + "/") @@ -99,7 +98,7 @@ func GetGithubDoc(client *http.Client, match map[string]string, installGOPATH, c for _, f := range r.File { absPath := strings.Replace(f.FileInfo().Name(), shaName, installPath, 1) - // Check if it is directory or not. + // Check if it is a directory. if strings.HasSuffix(absPath, "/") { // Directory. // Check if current directory is example. @@ -116,7 +115,7 @@ func GetGithubDoc(client *http.Client, match map[string]string, installGOPATH, c } // Create diretory before create file. - os.MkdirAll(path.Dir(absPath), os.ModePerm) + os.MkdirAll(path.Dir(absPath)+"/", os.ModePerm) // Write data to file fw, _ := os.Create(absPath) @@ -133,7 +132,7 @@ func GetGithubDoc(client *http.Client, match map[string]string, installGOPATH, c } pkg := &Package{ - ImportPath: importPath, + ImportPath: match["importPath"], AbsPath: installPath, Commit: commit, } @@ -143,7 +142,7 @@ func GetGithubDoc(client *http.Client, match map[string]string, installGOPATH, c // Check if need to check imports. if isCheckImport { for _, d := range dirs { - imports, err = checkImports(d, importPath) + imports, err = checkImports(d, match["importPath"]) if err != nil { return nil, nil, err } diff --git a/doc/google.go b/doc/google.go index 825124953..bfac52d13 100644 --- a/doc/google.go +++ b/doc/google.go @@ -75,8 +75,7 @@ func GetGoogleDoc(client *http.Client, match map[string]string, installGOPATH, c errors.New("doc.GetGoogleDoc(): Could not find revision for " + match["importPath"]) } - importPath := "code.google.com/p/" + expand("{repo}{dir}", match) - installPath := installGOPATH + "/src/" + importPath + installPath := installGOPATH + "/src/" + match["importPath"] // Remove old files. os.RemoveAll(installPath + "/") @@ -133,7 +132,7 @@ func GetGoogleDoc(client *http.Client, match map[string]string, installGOPATH, c } pkg := &Package{ - ImportPath: importPath, + ImportPath: match["importPath"], AbsPath: installPath, Commit: commit, } @@ -153,9 +152,9 @@ func GetGoogleDoc(client *http.Client, match map[string]string, installGOPATH, c } for _, d := range dirs { - if d.IsDir() { + if d.IsDir() && !(!cmdFlags["-e"] && strings.Contains(d.Name(), "example")) { absPath := installPath + "/" + d.Name() + "/" - imports, err = checkImports(absPath, importPath) + imports, err = checkImports(absPath, match["importPath"]) if err != nil { return nil, nil, err } diff --git a/doc/launchpad.go b/doc/launchpad.go new file mode 100644 index 000000000..965ce54bd --- /dev/null +++ b/doc/launchpad.go @@ -0,0 +1,141 @@ +// Copyright (c) 2013 GPMGo Members. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package doc + +import ( + "archive/tar" + "bytes" + "compress/gzip" + "io" + "net/http" + "os" + "path" + "regexp" + "strings" +) + +var LaunchpadPattern = regexp.MustCompile(`^launchpad\.net/(?P(?P[a-z0-9A-Z_.\-]+)(?P/[a-z0-9A-Z_.\-]+)?|~[a-z0-9A-Z_.\-]+/(\+junk|[a-z0-9A-Z_.\-]+)/[a-z0-9A-Z_.\-]+)(?P/[a-z0-9A-Z_.\-/]+)*$`) + +// GetLaunchpadDoc downloads tarball from launchpad.net. +func GetLaunchpadDoc(client *http.Client, match map[string]string, installGOPATH, commit string, cmdFlags map[string]bool) (*Package, []string, error) { + + if match["project"] != "" && match["series"] != "" { + rc, err := httpGet(client, expand("https://code.launchpad.net/{project}{series}/.bzr/branch-format", match), nil) + switch { + case err == nil: + rc.Close() + // The structure of the import path is launchpad.net/{root}/{dir}. + case isNotFound(err): + // The structure of the import path is is launchpad.net/{project}/{dir}. + match["repo"] = match["project"] + match["dir"] = expand("{series}{dir}", match) + default: + return nil, nil, err + } + } + + // bundle and snapshot will have commit 'B' and 'S', + // but does not need to download dependencies. + isCheckImport := len(commit) == 0 + + var downloadPath string + // Check if download with specific revision. + if isCheckImport || len(commit) == 1 { + downloadPath = expand("https://bazaar.launchpad.net/+branch/{repo}/tarball", match) + } else { + downloadPath = expand("https://bazaar.launchpad.net/+branch/{repo}/tarball/"+commit, match) + } + + // Scrape the repo browser to find the project revision and individual Go files. + p, err := httpGetBytes(client, downloadPath, nil) + if err != nil { + return nil, nil, err + } + + installPath := installGOPATH + "/src/" + match["importPath"] + + // Remove old files. + os.RemoveAll(installPath + "/") + // Create destination directory. + os.MkdirAll(installPath+"/", os.ModePerm) + + gzr, err := gzip.NewReader(bytes.NewReader(p)) + if err != nil { + return nil, nil, err + } + defer gzr.Close() + + tr := tar.NewReader(gzr) + + var autoPath string // Auto path is the root path that generated by bitbucket.org. + // Get source file data. + dirs := make([]string, 0, 5) + for { + h, err := tr.Next() + if err == io.EOF { + break + } else if err != nil { + return nil, nil, err + } + + fn := h.FileInfo().Name() + // Check root path. + if len(autoPath) == 0 { + autoPath = fn[:strings.Index(fn, match["repo"])+len(match["repo"])] + } + absPath := strings.Replace(fn, autoPath, installPath, 1) + + // Check if it is a directory. + if h.FileInfo().IsDir() { + // Directory. + // Check if current directory is example. + if !(!cmdFlags["-e"] && strings.Contains(absPath, "example")) { + dirs = append(dirs, absPath) + } + continue + } + + // Create diretory before create file. + os.MkdirAll(path.Dir(absPath)+"/", os.ModePerm) + + // Get data from archive. + fbytes := make([]byte, h.Size) + if _, err := io.ReadFull(tr, fbytes); err != nil { + return nil, nil, err + } + + // Write data to file + fw, err := os.Create(absPath) + if err != nil { + return nil, nil, err + } + + _, err = fw.Write(fbytes) + fw.Close() + if err != nil { + return nil, nil, err + } + } + + pkg := &Package{ + ImportPath: match["importPath"], + AbsPath: installPath, + Commit: commit, + } + + var imports []string + + // Check if need to check imports. + if isCheckImport { + for _, d := range dirs { + imports, err = checkImports(d+"/", match["importPath"]) + if err != nil { + return nil, nil, err + } + } + } + + return pkg, imports, err +} diff --git a/install.go b/install.go index c623455b7..33f0be988 100644 --- a/install.go +++ b/install.go @@ -219,7 +219,7 @@ var services = []*service{ {doc.GithubPattern, "github.com/", doc.GetGithubDoc}, {doc.GooglePattern, "code.google.com/", doc.GetGoogleDoc}, {doc.BitbucketPattern, "bitbucket.org/", doc.GetBitbucketDoc}, - //{launchpadPattern, "launchpad.net/", getLaunchpadDoc}, + {doc.LaunchpadPattern, "launchpad.net/", doc.GetLaunchpadDoc}, } // pureDownload downloads package without version control.