mirror of https://github.com/gogits/gogs.git
Meaglith Ma
11 years ago
37 changed files with 5652 additions and 28 deletions
@ -1,28 +1,25 @@
|
||||
[target] |
||||
path=github.com/gogits/gogs |
||||
path = github.com/gogits/gogs |
||||
|
||||
[deps] |
||||
github.com/codegangsta/cli= |
||||
github.com/go-martini/martini= |
||||
github.com/Unknwon/com= |
||||
github.com/Unknwon/cae= |
||||
github.com/Unknwon/goconfig= |
||||
github.com/dchest/scrypt= |
||||
github.com/nfnt/resize= |
||||
github.com/lunny/xorm= |
||||
github.com/go-sql-driver/mysql= |
||||
github.com/lib/pq= |
||||
github.com/gogits/logs= |
||||
github.com/gogits/binding= |
||||
github.com/gogits/git= |
||||
github.com/gogits/gfm= |
||||
github.com/gogits/cache= |
||||
github.com/gogits/session= |
||||
github.com/gogits/webdav= |
||||
github.com/martini-contrib/oauth2= |
||||
github.com/martini-contrib/sessions= |
||||
code.google.com/p/goauth2= |
||||
github.com/codegangsta/cli = |
||||
github.com/go-martini/martini = |
||||
github.com/Unknwon/com = |
||||
github.com/Unknwon/cae = |
||||
github.com/Unknwon/goconfig = |
||||
github.com/nfnt/resize = |
||||
github.com/lunny/xorm = |
||||
github.com/go-sql-driver/mysql = |
||||
github.com/lib/pq = |
||||
github.com/qiniu/log = |
||||
code.google.com/p/goauth2 = |
||||
github.com/gogits/logs = |
||||
github.com/gogits/binding = |
||||
github.com/gogits/git = |
||||
github.com/gogits/gfm = |
||||
github.com/gogits/cache = |
||||
github.com/gogits/session = |
||||
github.com/gogits/webdav = |
||||
|
||||
[res] |
||||
include=templates|public|conf |
||||
|
||||
include = templates|public|conf |
@ -0,0 +1,191 @@
|
||||
// Copyright 2013-2014 gopm authors.
|
||||
//
|
||||
// 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.
|
||||
|
||||
package cmd |
||||
|
||||
import ( |
||||
"fmt" |
||||
"os" |
||||
"path" |
||||
"path/filepath" |
||||
"runtime" |
||||
"strings" |
||||
|
||||
"github.com/Unknwon/com" |
||||
"github.com/codegangsta/cli" |
||||
|
||||
"github.com/gpmgo/gopm/doc" |
||||
"github.com/gpmgo/gopm/log" |
||||
) |
||||
|
||||
var CmdBin = cli.Command{ |
||||
Name: "bin", |
||||
Usage: "download and link dependencies and build executable binary", |
||||
Description: `Command bin downloads and links dependencies according to gopmfile, |
||||
and build executable binary to work directory |
||||
|
||||
gopm bin <import path>@[<tag|commit|branch>:<value>] |
||||
gopm bin <package name>@[<tag|commit|branch>:<value>] |
||||
|
||||
Can only specify one each time, and only works for projects that
|
||||
contain main package`, |
||||
Action: runBin, |
||||
Flags: []cli.Flag{ |
||||
cli.BoolFlag{"dir, d", "build binary to given directory(second argument)"}, |
||||
cli.BoolFlag{"update, u", "update pakcage(s) and dependencies if any"}, |
||||
cli.BoolFlag{"verbose, v", "show process details"}, |
||||
}, |
||||
} |
||||
|
||||
func runBin(ctx *cli.Context) { |
||||
setup(ctx) |
||||
|
||||
if len(ctx.Args()) == 0 { |
||||
log.Error("bin", "Cannot start command:") |
||||
log.Fatal("", "\tNo package specified") |
||||
} |
||||
|
||||
installRepoPath = doc.HomeDir + "/repos" |
||||
log.Log("Local repository path: %s", installRepoPath) |
||||
|
||||
// Check arguments.
|
||||
num := 1 |
||||
if ctx.Bool("dir") { |
||||
num = 2 |
||||
} |
||||
if len(ctx.Args()) != num { |
||||
log.Error("bin", "Cannot start command:") |
||||
log.Fatal("", "\tMissing indicated path to build binary") |
||||
} |
||||
|
||||
// Check if given directory exists.
|
||||
if ctx.Bool("dir") && !com.IsDir(ctx.Args()[1]) { |
||||
log.Error("bin", "Cannot start command:") |
||||
log.Fatal("", "\tIndicated path does not exist or is not a directory") |
||||
} |
||||
|
||||
// Parse package version.
|
||||
info := ctx.Args()[0] |
||||
pkgPath := info |
||||
node := doc.NewNode(pkgPath, pkgPath, doc.BRANCH, "", true) |
||||
var err error |
||||
if i := strings.Index(info, "@"); i > -1 { |
||||
pkgPath = info[:i] |
||||
node.ImportPath = pkgPath |
||||
node.DownloadURL = pkgPath |
||||
node.Type, node.Value = validPath(info[i+1:]) |
||||
} |
||||
|
||||
// Check package name.
|
||||
if !strings.Contains(pkgPath, "/") { |
||||
pkgPath = doc.GetPkgFullPath(pkgPath) |
||||
} |
||||
|
||||
// Get code.
|
||||
downloadPackages(ctx, []*doc.Node{node}) |
||||
|
||||
// Check if previous steps were successful.
|
||||
repoPath := installRepoPath + "/" + pkgPath + versionSuffix(node.Value) |
||||
if !com.IsDir(repoPath) { |
||||
log.Error("bin", "Cannot continue command:") |
||||
log.Fatal("", "\tPrevious steps weren't successful") |
||||
} |
||||
|
||||
wd, err := os.Getwd() |
||||
if err != nil { |
||||
log.Error("bin", "Cannot get work directory:") |
||||
log.Fatal("", "\t"+err.Error()) |
||||
} |
||||
|
||||
// Change to repository path.
|
||||
log.Log("Changing work directory to %s", repoPath) |
||||
if err = os.Chdir(repoPath); err != nil { |
||||
log.Error("bin", "Fail to change work directory:") |
||||
log.Fatal("", "\t"+err.Error()) |
||||
} |
||||
|
||||
// Build application.
|
||||
buildBinary(ctx) |
||||
defer func() { |
||||
// Clean files.
|
||||
os.RemoveAll(path.Join(repoPath, doc.VENDOR)) |
||||
}() |
||||
|
||||
includes := make([]string, 0, 3) |
||||
// Check if previous steps were successful.
|
||||
if com.IsFile(doc.GOPM_FILE_NAME) { |
||||
log.Trace("Loading gopmfile...") |
||||
gf := doc.NewGopmfile(".") |
||||
|
||||
var err error |
||||
pkgName, err = gf.GetValue("target", "path") |
||||
if err == nil { |
||||
log.Log("Target name: %s", pkgName) |
||||
} |
||||
|
||||
includes = strings.Split(gf.MustValue("res", "include"), "|") |
||||
} |
||||
|
||||
if len(pkgName) == 0 { |
||||
_, pkgName = filepath.Split(pkgPath) |
||||
} |
||||
|
||||
// Because build command moved binary to root path.
|
||||
binName := path.Base(pkgName) |
||||
if runtime.GOOS == "windows" { |
||||
binName += ".exe" |
||||
} |
||||
if !com.IsFile(binName) { |
||||
log.Error("bin", "Binary does not exist:") |
||||
log.Error("", "\t"+binName) |
||||
log.Fatal("", "\tPrevious steps weren't successful or the project does not contain main package") |
||||
} |
||||
|
||||
// Move binary to given directory.
|
||||
movePath := wd |
||||
if ctx.Bool("dir") { |
||||
movePath = ctx.Args()[1] |
||||
} |
||||
|
||||
if com.IsExist(movePath + "/" + binName) { |
||||
if err = os.Remove(movePath + "/" + binName); err != nil { |
||||
log.Warn("Cannot remove binary in work directory:") |
||||
log.Warn("\t %s", err) |
||||
} |
||||
} |
||||
|
||||
if err = os.Rename(binName, movePath+"/"+binName); err != nil { |
||||
log.Error("bin", "Fail to move binary:") |
||||
log.Fatal("", "\t"+err.Error()) |
||||
} |
||||
os.Chmod(movePath+"/"+binName, os.ModePerm) |
||||
|
||||
if len(includes) > 0 { |
||||
log.Log("Copying resources to %s", movePath) |
||||
for _, include := range includes { |
||||
if com.IsDir(include) { |
||||
if err = com.CopyDir(include, filepath.Join(movePath, include)); err != nil { |
||||
log.Error("bin", "Fail to copy following resource:") |
||||
log.Error("", "\t"+include) |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
log.Log("Changing work directory back to %s", wd) |
||||
os.Chdir(wd) |
||||
|
||||
log.Success("SUCC", "bin", "Command executed successfully!") |
||||
fmt.Println("Binary has been built into: " + movePath) |
||||
} |
@ -0,0 +1,86 @@
|
||||
// Copyright 2013 gopm authors.
|
||||
//
|
||||
// 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.
|
||||
|
||||
package cmd |
||||
|
||||
import ( |
||||
"os" |
||||
"path" |
||||
"path/filepath" |
||||
|
||||
"github.com/Unknwon/com" |
||||
"github.com/codegangsta/cli" |
||||
|
||||
"github.com/gpmgo/gopm/doc" |
||||
"github.com/gpmgo/gopm/log" |
||||
) |
||||
|
||||
var CmdBuild = cli.Command{ |
||||
Name: "build", |
||||
Usage: "link dependencies and go build", |
||||
Description: `Command build links dependencies according to gopmfile, |
||||
and execute 'go build' |
||||
|
||||
gopm build <go build commands>`, |
||||
Action: runBuild, |
||||
Flags: []cli.Flag{ |
||||
cli.BoolFlag{"update, u", "update pakcage(s) and dependencies if any"}, |
||||
cli.BoolFlag{"verbose, v", "show process details"}, |
||||
}, |
||||
} |
||||
|
||||
func runBuild(ctx *cli.Context) { |
||||
setup(ctx) |
||||
|
||||
// Get GOPATH.
|
||||
installGopath = com.GetGOPATHs()[0] |
||||
if com.IsDir(installGopath) { |
||||
isHasGopath = true |
||||
log.Log("Indicated GOPATH: %s", installGopath) |
||||
installGopath += "/src" |
||||
} |
||||
|
||||
buildBinary(ctx, ctx.Args()...) |
||||
log.Success("SUCC", "build", "Command executed successfully!") |
||||
} |
||||
|
||||
func buildBinary(ctx *cli.Context, args ...string) { |
||||
genNewGoPath(ctx, false) |
||||
|
||||
log.Trace("Building...") |
||||
|
||||
cmdArgs := []string{"go", "build"} |
||||
cmdArgs = append(cmdArgs, args...) |
||||
err := execCmd(newGoPath, newCurPath, cmdArgs...) |
||||
if err != nil { |
||||
log.Error("build", "fail to build program:") |
||||
log.Fatal("", "\t"+err.Error()) |
||||
} |
||||
|
||||
if isWindowsXP { |
||||
fName := path.Base(pkgName) |
||||
binName := fName + ".exe" |
||||
os.Remove(binName) |
||||
exePath := filepath.Join(curPath, doc.VENDOR, "src", pkgName, binName) |
||||
if com.IsFile(exePath) { |
||||
err = os.Rename(exePath, filepath.Join(curPath, binName)) |
||||
if err != nil { |
||||
log.Error("build", "fail to move binary:") |
||||
log.Fatal("", "\t"+err.Error()) |
||||
} |
||||
} else { |
||||
log.Warn("No binary generated") |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,88 @@
|
||||
// Copyright 2013-2014 gopm authors.
|
||||
//
|
||||
// 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.
|
||||
|
||||
package cmd |
||||
|
||||
import ( |
||||
"os" |
||||
"strings" |
||||
|
||||
"github.com/Unknwon/com" |
||||
"github.com/codegangsta/cli" |
||||
|
||||
"github.com/gpmgo/gopm/doc" |
||||
"github.com/gpmgo/gopm/log" |
||||
) |
||||
|
||||
var ( |
||||
workDir string // The path of gopm was executed.
|
||||
) |
||||
|
||||
// setup initialize common environment for commands.
|
||||
func setup(ctx *cli.Context) { |
||||
var err error |
||||
workDir, err = os.Getwd() |
||||
if err != nil { |
||||
log.Error("setup", "Fail to get work directory:") |
||||
log.Fatal("", "\t"+err.Error()) |
||||
} |
||||
|
||||
log.PureMode = ctx.GlobalBool("noterm") |
||||
log.Verbose = ctx.Bool("verbose") |
||||
} |
||||
|
||||
// parseTarget returns "." when target is empty string.
|
||||
func parseTarget(target string) string { |
||||
if len(target) == 0 { |
||||
target = "." |
||||
} |
||||
return target |
||||
} |
||||
|
||||
// validPath checks if the information of the package is valid.
|
||||
func validPath(info string) (string, string) { |
||||
infos := strings.Split(info, ":") |
||||
|
||||
l := len(infos) |
||||
switch { |
||||
case l == 1: |
||||
// For local imports.
|
||||
if com.IsFile(infos[0]) { |
||||
return doc.LOCAL, infos[0] |
||||
} |
||||
case l == 2: |
||||
switch infos[1] { |
||||
case doc.TRUNK, doc.MASTER, doc.DEFAULT: |
||||
infos[1] = "" |
||||
} |
||||
return infos[0], infos[1] |
||||
} |
||||
|
||||
log.Error("", "Cannot parse dependency version:") |
||||
log.Error("", "\t"+info) |
||||
log.Help("Try 'gopm help get' to get more information") |
||||
return "", "" |
||||
} |
||||
|
||||
func versionSuffix(value string) string { |
||||
if len(value) > 0 { |
||||
return "." + value |
||||
} |
||||
return "" |
||||
} |
||||
|
||||
func isSubpackage(rootPath, targetPath string) bool { |
||||
return strings.HasSuffix(strings.Replace(workDir, "\\", "/", -1), rootPath) || |
||||
strings.HasPrefix(rootPath, targetPath) |
||||
} |
@ -0,0 +1,31 @@
|
||||
// Copyright 2013-2014 gopm authors.
|
||||
//
|
||||
// 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.
|
||||
|
||||
package cmd |
||||
|
||||
import ( |
||||
"testing" |
||||
|
||||
. "github.com/smartystreets/goconvey/convey" |
||||
) |
||||
|
||||
func Test_parseTarget(t *testing.T) { |
||||
Convey("Target is empty", t, func() { |
||||
So(parseTarget(""), ShouldEqual, ".") |
||||
}) |
||||
|
||||
Convey("Target is not empty", t, func() { |
||||
So(parseTarget("github.com/gpmgo/gopm"), ShouldEqual, "github.com/gpmgo/gopm") |
||||
}) |
||||
} |
@ -0,0 +1,60 @@
|
||||
// Copyright 2013-2014 gopm authors.
|
||||
//
|
||||
// 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.
|
||||
|
||||
package cmd |
||||
|
||||
import ( |
||||
"path" |
||||
|
||||
"github.com/Unknwon/goconfig" |
||||
"github.com/codegangsta/cli" |
||||
|
||||
"github.com/gpmgo/gopm/doc" |
||||
"github.com/gpmgo/gopm/log" |
||||
) |
||||
|
||||
var CmdConfig = cli.Command{ |
||||
Name: "config", |
||||
Usage: "configurate gopm global settings", |
||||
Description: `Command config configurates gopm global settings |
||||
|
||||
gopm config github [client_id] [client_secret] |
||||
`, |
||||
Action: runConfig, |
||||
Flags: []cli.Flag{ |
||||
cli.BoolFlag{"verbose, v", "show process details"}, |
||||
}, |
||||
} |
||||
|
||||
func runConfig(ctx *cli.Context) { |
||||
setup(ctx) |
||||
|
||||
if len(ctx.Args()) == 0 { |
||||
log.Error("config", "Cannot start command:") |
||||
log.Fatal("", "\tNo section specified") |
||||
} |
||||
|
||||
switch ctx.Args()[0] { |
||||
case "github": |
||||
if len(ctx.Args()) < 3 { |
||||
log.Error("config", "Cannot config section 'github'") |
||||
log.Fatal("", "\tNot enough arguments for client_id and client_secret") |
||||
} |
||||
doc.Cfg.SetValue("github", "client_id", ctx.Args()[1]) |
||||
doc.Cfg.SetValue("github", "client_secret", ctx.Args()[2]) |
||||
goconfig.SaveConfigFile(doc.Cfg, path.Join(doc.HomeDir, doc.GOPM_CONFIG_FILE)) |
||||
} |
||||
|
||||
log.Success("SUCC", "config", "Command executed successfully!") |
||||
} |
@ -0,0 +1,91 @@
|
||||
// Copyright 2013-2014 gopm authors.
|
||||
//
|
||||
// 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.
|
||||
|
||||
package cmd |
||||
|
||||
import ( |
||||
"os" |
||||
"strings" |
||||
|
||||
"github.com/Unknwon/com" |
||||
"github.com/Unknwon/goconfig" |
||||
"github.com/codegangsta/cli" |
||||
|
||||
"github.com/gpmgo/gopm/doc" |
||||
"github.com/gpmgo/gopm/log" |
||||
) |
||||
|
||||
var CmdGen = cli.Command{ |
||||
Name: "gen", |
||||
Usage: "generate a gopmfile according current Go project", |
||||
Description: `Command gen gets dependencies and generates a gopmfile |
||||
|
||||
gopm gen |
||||
|
||||
Make sure you run this command in the root path of a go project.`, |
||||
Action: runGen, |
||||
Flags: []cli.Flag{ |
||||
cli.BoolFlag{"example, e", "check dependencies for example(s)"}, |
||||
cli.BoolFlag{"verbose, v", "show process details"}, |
||||
}, |
||||
} |
||||
|
||||
var commonRes = []string{"views", "templates", "static", "public", "conf"} |
||||
|
||||
func runGen(ctx *cli.Context) { |
||||
setup(ctx) |
||||
|
||||
if !com.IsExist(".gopmfile") { |
||||
os.Create(".gopmfile") |
||||
} |
||||
|
||||
gf, err := goconfig.LoadConfigFile(".gopmfile") |
||||
if err != nil { |
||||
log.Error("gen", "Cannot load gopmfile:") |
||||
log.Fatal("", "\t"+err.Error()) |
||||
} |
||||
|
||||
targetPath := parseTarget(gf.MustValue("target", "path")) |
||||
// Get and set dependencies.
|
||||
imports := doc.GetAllImports([]string{workDir}, targetPath, ctx.Bool("example"), false) |
||||
for _, p := range imports { |
||||
p = doc.GetProjectPath(p) |
||||
// Skip subpackage(s) of current project.
|
||||
if isSubpackage(p, targetPath) { |
||||
continue |
||||
} |
||||
|
||||
// Check if user specified the version.
|
||||
if value := gf.MustValue("deps", p); len(value) == 0 { |
||||
gf.SetValue("deps", p, "") |
||||
} |
||||
} |
||||
|
||||
// Get and set resources.
|
||||
res := make([]string, 0, len(commonRes)) |
||||
for _, cr := range commonRes { |
||||
if com.IsExist(cr) { |
||||
res = append(res, cr) |
||||
} |
||||
} |
||||
gf.SetValue("res", "include", strings.Join(res, "|")) |
||||
|
||||
err = goconfig.SaveConfigFile(gf, ".gopmfile") |
||||
if err != nil { |
||||
log.Error("gen", "Fail to save gopmfile:") |
||||
log.Fatal("", "\t"+err.Error()) |
||||
} |
||||
|
||||
log.Success("SUCC", "gen", "Generate gopmfile successfully!") |
||||
} |
@ -0,0 +1,402 @@
|
||||
// Copyright 2013-2014 gopm authors.
|
||||
//
|
||||
// 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.
|
||||
|
||||
package cmd |
||||
|
||||
import ( |
||||
"fmt" |
||||
"os" |
||||
"path" |
||||
"strings" |
||||
|
||||
"github.com/Unknwon/com" |
||||
"github.com/Unknwon/goconfig" |
||||
"github.com/codegangsta/cli" |
||||
|
||||
"github.com/gpmgo/gopm/doc" |
||||
"github.com/gpmgo/gopm/log" |
||||
) |
||||
|
||||
var ( |
||||
installRepoPath string // The path of gopm local repository.
|
||||
installGopath string // The first path in the GOPATH.
|
||||
isHasGopath bool // Indicates whether system has GOPATH.
|
||||
|
||||
downloadCache map[string]bool // Saves packages that have been downloaded.
|
||||
downloadCount int |
||||
failConut int |
||||
) |
||||
|
||||
var CmdGet = cli.Command{ |
||||
Name: "get", |
||||
Usage: "fetch remote package(s) and dependencies to local repository", |
||||
Description: `Command get fetches a package, and any pakcage that it depents on.
|
||||
If the package has a gopmfile, the fetch process will be driven by that. |
||||
|
||||
gopm get |
||||
gopm get <import path>@[<tag|commit|branch>:<value>] |
||||
gopm get <package name>@[<tag|commit|branch>:<value>] |
||||
|
||||
Can specify one or more: gopm get beego@tag:v0.9.0 github.com/beego/bee |
||||
|
||||
If no version specified and package exists in GOPATH, |
||||
it will be skipped unless user enabled '--remote, -r' option
|
||||
then all the packages go into gopm local repository.`, |
||||
Action: runGet, |
||||
Flags: []cli.Flag{ |
||||
cli.BoolFlag{"gopath, g", "download all pakcages to GOPATH"}, |
||||
cli.BoolFlag{"update, u", "update pakcage(s) and dependencies if any"}, |
||||
cli.BoolFlag{"example, e", "download dependencies for example folder"}, |
||||
cli.BoolFlag{"remote, r", "download all pakcages to gopm local repository"}, |
||||
cli.BoolFlag{"verbose, v", "show process details"}, |
||||
}, |
||||
} |
||||
|
||||
func init() { |
||||
downloadCache = make(map[string]bool) |
||||
} |
||||
|
||||
func runGet(ctx *cli.Context) { |
||||
setup(ctx) |
||||
// Check conflicts.
|
||||
if ctx.Bool("gopath") && ctx.Bool("remote") { |
||||
log.Error("get", "Command options have conflicts") |
||||
log.Error("", "Following options are not supposed to use at same time:") |
||||
log.Error("", "\t'--gopath, -g' '--remote, -r'") |
||||
log.Help("Try 'gopm help get' to get more information") |
||||
} |
||||
|
||||
if !ctx.Bool("remote") { |
||||
// Get GOPATH.
|
||||
installGopath = com.GetGOPATHs()[0] |
||||
if com.IsDir(installGopath) { |
||||
isHasGopath = true |
||||
log.Log("Indicated GOPATH: %s", installGopath) |
||||
installGopath += "/src" |
||||
} else { |
||||
if ctx.Bool("gopath") { |
||||
log.Error("get", "Invalid GOPATH path") |
||||
log.Error("", "GOPATH does not exist or is not a directory:") |
||||
log.Error("", "\t"+installGopath) |
||||
log.Help("Try 'go help gopath' to get more information") |
||||
} else { |
||||
// It's OK that no GOPATH setting
|
||||
// when user does not specify to use.
|
||||
log.Warn("No GOPATH setting available") |
||||
} |
||||
} |
||||
} |
||||
|
||||
// The gopm local repository.
|
||||
installRepoPath = path.Join(doc.HomeDir, "repos") |
||||
log.Log("Local repository path: %s", installRepoPath) |
||||
|
||||
// Check number of arguments to decide which function to call.
|
||||
switch len(ctx.Args()) { |
||||
case 0: |
||||
getByGopmfile(ctx) |
||||
case 1: |
||||
getByPath(ctx) |
||||
default: |
||||
log.Error("get", "too many arguments") |
||||
log.Help("Try 'gopm help get' to get more information") |
||||
} |
||||
} |
||||
|
||||
func getByGopmfile(ctx *cli.Context) { |
||||
// Check if gopmfile exists and generate one if not.
|
||||
if !com.IsFile(".gopmfile") { |
||||
runGen(ctx) |
||||
} |
||||
gf := doc.NewGopmfile(".") |
||||
|
||||
targetPath := parseTarget(gf.MustValue("target", "path")) |
||||
// Get dependencies.
|
||||
imports := doc.GetAllImports([]string{workDir}, targetPath, ctx.Bool("example"), false) |
||||
|
||||
nodes := make([]*doc.Node, 0, len(imports)) |
||||
for _, p := range imports { |
||||
// TODO: DOING TEST CASES!!!
|
||||
p = doc.GetProjectPath(p) |
||||
// Skip subpackage(s) of current project.
|
||||
if isSubpackage(p, targetPath) { |
||||
continue |
||||
} |
||||
node := doc.NewNode(p, p, doc.BRANCH, "", true) |
||||
|
||||
// Check if user specified the version.
|
||||
if v, err := gf.GetValue("deps", p); err == nil && len(v) > 0 { |
||||
node.Type, node.Value = validPath(v) |
||||
} |
||||
nodes = append(nodes, node) |
||||
} |
||||
|
||||
downloadPackages(ctx, nodes) |
||||
doc.SaveLocalNodes() |
||||
|
||||
log.Log("%d package(s) downloaded, %d failed", downloadCount, failConut) |
||||
} |
||||
|
||||
func getByPath(ctx *cli.Context) { |
||||
nodes := make([]*doc.Node, 0, len(ctx.Args())) |
||||
for _, info := range ctx.Args() { |
||||
pkgPath := info |
||||
node := doc.NewNode(pkgPath, pkgPath, doc.BRANCH, "", true) |
||||
|
||||
if i := strings.Index(info, "@"); i > -1 { |
||||
pkgPath = info[:i] |
||||
tp, ver := validPath(info[i+1:]) |
||||
node = doc.NewNode(pkgPath, pkgPath, tp, ver, true) |
||||
} |
||||
|
||||
// Check package name.
|
||||
if !strings.Contains(pkgPath, "/") { |
||||
pkgPath = doc.GetPkgFullPath(pkgPath) |
||||
} |
||||
|
||||
nodes = append(nodes, node) |
||||
} |
||||
|
||||
downloadPackages(ctx, nodes) |
||||
doc.SaveLocalNodes() |
||||
|
||||
log.Log("%d package(s) downloaded, %d failed", downloadCount, failConut) |
||||
} |
||||
|
||||
func copyToGopath(srcPath, destPath string) { |
||||
importPath := strings.TrimPrefix(destPath, installGopath+"/") |
||||
if len(getVcsName(destPath)) > 0 { |
||||
log.Warn("Package in GOPATH has version control: %s", importPath) |
||||
return |
||||
} |
||||
|
||||
os.RemoveAll(destPath) |
||||
err := com.CopyDir(srcPath, destPath) |
||||
if err != nil { |
||||
log.Error("download", "Fail to copy to GOPATH:") |
||||
log.Fatal("", "\t"+err.Error()) |
||||
} |
||||
|
||||
log.Log("Package copied to GOPATH: %s", importPath) |
||||
} |
||||
|
||||
// downloadPackages downloads packages with certain commit,
|
||||
// if the commit is empty string, then it downloads all dependencies,
|
||||
// otherwise, it only downloada package with specific commit only.
|
||||
func downloadPackages(ctx *cli.Context, nodes []*doc.Node) { |
||||
// Check all packages, they may be raw packages path.
|
||||
for _, n := range nodes { |
||||
// Check if local reference
|
||||
if n.Type == doc.LOCAL { |
||||
continue |
||||
} |
||||
// Check if it is a valid remote path or C.
|
||||
if n.ImportPath == "C" { |
||||
continue |
||||
} else if !doc.IsValidRemotePath(n.ImportPath) { |
||||
// Invalid import path.
|
||||
log.Error("download", "Skipped invalid package: "+fmt.Sprintf("%s@%s:%s", |
||||
n.ImportPath, n.Type, doc.CheckNodeValue(n.Value))) |
||||
failConut++ |
||||
continue |
||||
} |
||||
|
||||
// Valid import path.
|
||||
gopathDir := path.Join(installGopath, n.ImportPath) |
||||
n.RootPath = doc.GetProjectPath(n.ImportPath) |
||||
installPath := path.Join(installRepoPath, n.RootPath) + versionSuffix(n.Value) |
||||
|
||||
if isSubpackage(n.RootPath, ".") { |
||||
continue |
||||
} |
||||
|
||||
// Indicates whether need to download package again.
|
||||
if n.IsFixed() && com.IsExist(installPath) { |
||||
n.IsGetDepsOnly = true |
||||
} |
||||
|
||||
if !ctx.Bool("update") { |
||||
// Check if package has been downloaded.
|
||||
if (len(n.Value) == 0 && !ctx.Bool("remote") && com.IsExist(gopathDir)) || |
||||
com.IsExist(installPath) { |
||||
log.Trace("Skipped installed package: %s@%s:%s", |
||||
n.ImportPath, n.Type, doc.CheckNodeValue(n.Value)) |
||||
|
||||
// Only copy when no version control.
|
||||
if ctx.Bool("gopath") && (com.IsExist(installPath) || |
||||
len(getVcsName(gopathDir)) == 0) { |
||||
copyToGopath(installPath, gopathDir) |
||||
} |
||||
continue |
||||
} else { |
||||
doc.LocalNodes.SetValue(n.RootPath, "value", "") |
||||
} |
||||
} |
||||
|
||||
if downloadCache[n.RootPath] { |
||||
log.Trace("Skipped downloaded package: %s@%s:%s", |
||||
n.ImportPath, n.Type, doc.CheckNodeValue(n.Value)) |
||||
continue |
||||
} |
||||
|
||||
// Download package.
|
||||
nod, imports := downloadPackage(ctx, n) |
||||
if len(imports) > 0 { |
||||
var gf *goconfig.ConfigFile |
||||
|
||||
// Check if has gopmfile.
|
||||
if com.IsFile(installPath + "/" + doc.GOPM_FILE_NAME) { |
||||
log.Log("Found gopmfile: %s@%s:%s", |
||||
n.ImportPath, n.Type, doc.CheckNodeValue(n.Value)) |
||||
gf = doc.NewGopmfile(installPath) |
||||
} |
||||
|
||||
// Need to download dependencies.
|
||||
// Generate temporary nodes.
|
||||
nodes := make([]*doc.Node, len(imports)) |
||||
for i := range nodes { |
||||
nodes[i] = doc.NewNode(imports[i], imports[i], doc.BRANCH, "", true) |
||||
|
||||
if gf == nil { |
||||
continue |
||||
} |
||||
|
||||
// Check if user specified the version.
|
||||
if v, err := gf.GetValue("deps", imports[i]); err == nil && len(v) > 0 { |
||||
nodes[i].Type, nodes[i].Value = validPath(v) |
||||
} |
||||
} |
||||
downloadPackages(ctx, nodes) |
||||
} |
||||
|
||||
// Only save package information with specific commit.
|
||||
if nod == nil { |
||||
continue |
||||
} |
||||
|
||||
// Save record in local nodes.
|
||||
log.Success("SUCC", "GET", fmt.Sprintf("%s@%s:%s", |
||||
n.ImportPath, n.Type, doc.CheckNodeValue(n.Value))) |
||||
downloadCount++ |
||||
|
||||
// Only save non-commit node.
|
||||
if len(nod.Value) == 0 && len(nod.Revision) > 0 { |
||||
doc.LocalNodes.SetValue(nod.RootPath, "value", nod.Revision) |
||||
} |
||||
|
||||
if ctx.Bool("gopath") && com.IsExist(installPath) && !ctx.Bool("update") && |
||||
len(getVcsName(path.Join(installGopath, nod.RootPath))) == 0 { |
||||
copyToGopath(installPath, gopathDir) |
||||
} |
||||
} |
||||
} |
||||
|
||||
// downloadPackage downloads package either use version control tools or not.
|
||||
func downloadPackage(ctx *cli.Context, nod *doc.Node) (*doc.Node, []string) { |
||||
log.Message("Downloading", fmt.Sprintf("package: %s@%s:%s", |
||||
nod.ImportPath, nod.Type, doc.CheckNodeValue(nod.Value))) |
||||
// Mark as donwloaded.
|
||||
downloadCache[nod.RootPath] = true |
||||
|
||||
// Check if only need to use VCS tools.
|
||||
var imports []string |
||||
var err error |
||||
gopathDir := path.Join(installGopath, nod.RootPath) |
||||
vcs := getVcsName(gopathDir) |
||||
if ctx.Bool("update") && ctx.Bool("gopath") && len(vcs) > 0 { |
||||
err = updateByVcs(vcs, gopathDir) |
||||
imports = doc.GetAllImports([]string{gopathDir}, nod.RootPath, false, false) |
||||
} else { |
||||
// If package has revision and exist, then just check dependencies.
|
||||
if nod.IsGetDepsOnly { |
||||
return nod, doc.GetAllImports([]string{path.Join(installRepoPath, nod.RootPath) + versionSuffix(nod.Value)}, |
||||
nod.RootPath, ctx.Bool("example"), false) |
||||
} |
||||
nod.Revision = doc.LocalNodes.MustValue(nod.RootPath, "value") |
||||
imports, err = doc.PureDownload(nod, installRepoPath, ctx) //CmdGet.Flags)
|
||||
} |
||||
|
||||
if err != nil { |
||||
log.Error("get", "Fail to download pakage: "+nod.ImportPath) |
||||
log.Error("", "\t"+err.Error()) |
||||
failConut++ |
||||
os.RemoveAll(installRepoPath + "/" + nod.RootPath) |
||||
return nil, nil |
||||
} |
||||
return nod, imports |
||||
} |
||||
|
||||
func getVcsName(dirPath string) string { |
||||
switch { |
||||
case com.IsExist(path.Join(dirPath, ".git")): |
||||
return "git" |
||||
case com.IsExist(path.Join(dirPath, ".hg")): |
||||
return "hg" |
||||
case com.IsExist(path.Join(dirPath, ".svn")): |
||||
return "svn" |
||||
} |
||||
return "" |
||||
} |
||||
|
||||
func updateByVcs(vcs, dirPath string) error { |
||||
err := os.Chdir(dirPath) |
||||
if err != nil { |
||||
log.Error("Update by VCS", "Fail to change work directory:") |
||||
log.Fatal("", "\t"+err.Error()) |
||||
} |
||||
defer os.Chdir(workDir) |
||||
|
||||
switch vcs { |
||||
case "git": |
||||
branch, _, err := com.ExecCmd("git", "rev-parse", "--abbrev-ref", "HEAD") |
||||
if err != nil { |
||||
log.Error("", "Error occurs when 'git rev-parse --abbrev-ref HEAD'") |
||||
log.Error("", "\t"+err.Error()) |
||||
} |
||||
|
||||
_, _, err = com.ExecCmd("git", "pull", "origin", branch) |
||||
if err != nil { |
||||
log.Error("", "Error occurs when 'git pull origin "+branch+"'") |
||||
log.Error("", "\t"+err.Error()) |
||||
} |
||||
case "hg": |
||||
_, stderr, err := com.ExecCmd("hg", "pull") |
||||
if err != nil { |
||||
log.Error("", "Error occurs when 'hg pull'") |
||||
log.Error("", "\t"+err.Error()) |
||||
} |
||||
if len(stderr) > 0 { |
||||
log.Error("", "Error: "+stderr) |
||||
} |
||||
|
||||
_, stderr, err = com.ExecCmd("hg", "up") |
||||
if err != nil { |
||||
log.Error("", "Error occurs when 'hg up'") |
||||
log.Error("", "\t"+err.Error()) |
||||
} |
||||
if len(stderr) > 0 { |
||||
log.Error("", "Error: "+stderr) |
||||
} |
||||
case "svn": |
||||
_, stderr, err := com.ExecCmd("svn", "update") |
||||
if err != nil { |
||||
log.Error("", "Error occurs when 'svn update'") |
||||
log.Error("", "\t"+err.Error()) |
||||
} |
||||
if len(stderr) > 0 { |
||||
log.Error("", "Error: "+stderr) |
||||
} |
||||
} |
||||
return nil |
||||
} |
@ -0,0 +1,292 @@
|
||||
// Copyright 2013-2014 gopm authors.
|
||||
//
|
||||
// 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.
|
||||
|
||||
package cmd |
||||
|
||||
import ( |
||||
"errors" |
||||
"go/build" |
||||
"os" |
||||
"os/exec" |
||||
"path/filepath" |
||||
"runtime" |
||||
"strings" |
||||
|
||||
"github.com/Unknwon/com" |
||||
"github.com/codegangsta/cli" |
||||
|
||||
"github.com/gpmgo/gopm/doc" |
||||
"github.com/gpmgo/gopm/log" |
||||
) |
||||
|
||||
var isWindowsXP = false |
||||
|
||||
func getGopmPkgs(dirPath string, isTest bool) (pkgs map[string]*doc.Pkg, err error) { |
||||
absPath, err := filepath.Abs(dirPath) |
||||
if err != nil { |
||||
log.Error("", "Fail to get absolute path of work directory:") |
||||
log.Fatal("", "\t"+err.Error()) |
||||
} |
||||
|
||||
var builds map[string]string |
||||
|
||||
if com.IsFile(absPath + "/" + doc.GOPM_FILE_NAME) { |
||||
gf := doc.NewGopmfile(absPath) |
||||
|
||||
if builds, err = gf.GetSection("deps"); err != nil { |
||||
builds = nil |
||||
} |
||||
} |
||||
|
||||
imports := doc.GetAllImports([]string{dirPath}, ".", false, false) |
||||
pkgs = make(map[string]*doc.Pkg) |
||||
for _, name := range imports { |
||||
if name == "C" { |
||||
continue |
||||
} |
||||
if !doc.IsGoRepoPath(name) { |
||||
if builds != nil { |
||||
if info, ok := builds[name]; ok { |
||||
// Check version. there should chek
|
||||
// local first because d:\ contains :
|
||||
if com.IsDir(info) { |
||||
pkgs[name] = &doc.Pkg{ |
||||
ImportPath: name, |
||||
Type: doc.LOCAL, |
||||
Value: info, |
||||
} |
||||
continue |
||||
} else if i := strings.Index(info, ":"); i > -1 { |
||||
pkgs[name] = &doc.Pkg{ |
||||
ImportPath: name, |
||||
Type: info[:i], |
||||
Value: info[i+1:], |
||||
} |
||||
continue |
||||
} |
||||
} |
||||
} |
||||
pkgs[name] = doc.NewDefaultPkg(name) |
||||
} |
||||
} |
||||
return pkgs, nil |
||||
} |
||||
|
||||
func pkgInCache(name string, cachePkgs map[string]*doc.Pkg) bool { |
||||
_, ok := cachePkgs[name] |
||||
return ok |
||||
} |
||||
|
||||
func autoLink(oldPath, newPath string) error { |
||||
newPPath, _ := filepath.Split(newPath) |
||||
os.MkdirAll(newPPath, os.ModePerm) |
||||
return makeLink(oldPath, newPath) |
||||
} |
||||
|
||||
func getChildPkgs(ctx *cli.Context, cpath string, ppkg *doc.Pkg, cachePkgs map[string]*doc.Pkg, isTest bool) error { |
||||
pkgs, err := getGopmPkgs(cpath, isTest) |
||||
if err != nil { |
||||
return errors.New("Fail to get gopmfile deps: " + err.Error()) |
||||
} |
||||
for name, pkg := range pkgs { |
||||
pkg.RootPath = doc.GetProjectPath(pkg.ImportPath) |
||||
if !pkgInCache(pkg.RootPath, cachePkgs) { |
||||
var newPath string |
||||
if !build.IsLocalImport(name) && pkg.Type != doc.LOCAL { |
||||
suf := versionSuffix(pkg.Value) |
||||
pkgPath := strings.Replace( |
||||
pkg.ImportPath, pkg.RootPath, pkg.RootPath+suf, 1) |
||||
newPath = filepath.Join(installRepoPath, pkgPath) |
||||
if len(suf) == 0 && !ctx.Bool("remote") && |
||||
com.IsDir(filepath.Join(installGopath, pkgPath)) { |
||||
newPath = filepath.Join(installGopath, pkgPath) |
||||
} |
||||
if pkgName != "" && strings.HasPrefix(pkg.ImportPath, pkgName) { |
||||
newPath = filepath.Join(curPath, strings.TrimPrefix(pkg.ImportPath, pkgName)) |
||||
} else { |
||||
if !com.IsExist(newPath) || ctx.Bool("update") { |
||||
node := doc.NewNode(pkg.ImportPath, pkg.ImportPath, |
||||
pkg.Type, pkg.Value, true) |
||||
nodes := []*doc.Node{node} |
||||
downloadPackages(ctx, nodes) |
||||
// TODO: Should handler download failed
|
||||
} |
||||
} |
||||
} else { |
||||
if pkg.Type == doc.LOCAL { |
||||
newPath, err = filepath.Abs(pkg.Value) |
||||
} else { |
||||
newPath, err = filepath.Abs(name) |
||||
} |
||||
if err != nil { |
||||
return err |
||||
} |
||||
} |
||||
cachePkgs[pkg.RootPath] = pkg |
||||
err = getChildPkgs(ctx, newPath, pkg, cachePkgs, false) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
} |
||||
} |
||||
return nil |
||||
} |
||||
|
||||
var pkgName string |
||||
var curPath string |
||||
var newCurPath string |
||||
var newGoPath string |
||||
var oldGoPath string |
||||
|
||||
func execCmd(gopath, curPath string, args ...string) error { |
||||
cwd, err := os.Getwd() |
||||
if err != nil { |
||||
log.Error("", "Fail to get work directory:") |
||||
log.Fatal("", "\t"+err.Error()) |
||||
} |
||||
|
||||
log.Log("Changing work directory to %s", curPath) |
||||
err = os.Chdir(curPath) |
||||
if err != nil { |
||||
log.Error("", "Fail to change work directory:") |
||||
log.Fatal("", "\t"+err.Error()) |
||||
} |
||||
defer func() { |
||||
log.Log("Changing work directory back to %s", cwd) |
||||
os.Chdir(cwd) |
||||
}() |
||||
|
||||
err = os.Chdir(curPath) |
||||
if err != nil { |
||||
log.Error("", "Fail to change work directory:") |
||||
log.Fatal("", "\t"+err.Error()) |
||||
} |
||||
|
||||
oldGoPath = os.Getenv("GOPATH") |
||||
log.Log("Setting GOPATH to %s", gopath) |
||||
|
||||
sep := ":" |
||||
if runtime.GOOS == "windows" { |
||||
sep = ";" |
||||
} |
||||
err = os.Setenv("GOPATH", gopath+sep+oldGoPath) |
||||
if err != nil { |
||||
log.Error("", "Fail to setting GOPATH:") |
||||
log.Fatal("", "\t"+err.Error()) |
||||
} |
||||
defer func() { |
||||
log.Log("Setting GOPATH back to %s", oldGoPath) |
||||
os.Setenv("GOPATH", oldGoPath) |
||||
}() |
||||
|
||||
cmd := exec.Command(args[0], args[1:]...) |
||||
cmd.Stdout = os.Stdout |
||||
cmd.Stderr = os.Stderr |
||||
|
||||
log.Log("===== application outputs start =====\n") |
||||
|
||||
err = cmd.Run() |
||||
|
||||
log.Log("====== application outputs end ======") |
||||
return err |
||||
} |
||||
|
||||
func genNewGoPath(ctx *cli.Context, isTest bool) { |
||||
var err error |
||||
curPath, err = os.Getwd() |
||||
if err != nil { |
||||
log.Error("", "Fail to get work directory:") |
||||
log.Fatal("", "\t"+err.Error()) |
||||
} |
||||
|
||||
installRepoPath = doc.HomeDir + "/repos" |
||||
|
||||
if com.IsFile(curPath + "/" + doc.GOPM_FILE_NAME) { |
||||
log.Trace("Loading gopmfile...") |
||||
gf := doc.NewGopmfile(curPath) |
||||
|
||||
var err error |
||||
pkgName, err = gf.GetValue("target", "path") |
||||
if err == nil { |
||||
log.Log("Target name: %s", pkgName) |
||||
} |
||||
} |
||||
|
||||
if len(pkgName) == 0 { |
||||
_, pkgName = filepath.Split(curPath) |
||||
} |
||||
|
||||
cachePkgs := make(map[string]*doc.Pkg) |
||||
err = getChildPkgs(ctx, curPath, nil, cachePkgs, isTest) |
||||
if err != nil { |
||||
log.Error("", "Fail to get child pakcages:") |
||||
log.Fatal("", "\t"+err.Error()) |
||||
} |
||||
|
||||
newGoPath = filepath.Join(curPath, doc.VENDOR) |
||||
newGoPathSrc := filepath.Join(newGoPath, "src") |
||||
os.RemoveAll(newGoPathSrc) |
||||
os.MkdirAll(newGoPathSrc, os.ModePerm) |
||||
|
||||
for name, pkg := range cachePkgs { |
||||
suf := versionSuffix(pkg.Value) |
||||
|
||||
var oldPath string |
||||
if pkg.Type == doc.LOCAL { |
||||
oldPath, _ = filepath.Abs(pkg.Value) |
||||
} else { |
||||
oldPath = filepath.Join(installRepoPath, name) + suf |
||||
} |
||||
|
||||
newPath := filepath.Join(newGoPathSrc, name) |
||||
paths := strings.Split(name, "/") |
||||
var isExistP, isCurChild bool |
||||
if name == pkgName { |
||||
continue |
||||
} |
||||
|
||||
for i := 0; i < len(paths)-1; i++ { |
||||
pName := strings.Join(paths[:len(paths)-1-i], "/") |
||||
if _, ok := cachePkgs[pName]; ok { |
||||
isExistP = true |
||||
break |
||||
} |
||||
if pkgName == pName { |
||||
isCurChild = true |
||||
break |
||||
} |
||||
} |
||||
if isCurChild { |
||||
continue |
||||
} |
||||
|
||||
if !isExistP && (len(pkg.Value) > 0 || ctx.Bool("remote") || |
||||
!com.IsDir(filepath.Join(installGopath, pkg.ImportPath))) { |
||||
log.Log("Linking %s", name+suf) |
||||
err = autoLink(oldPath, newPath) |
||||
if err != nil { |
||||
log.Error("", "Fail to make link:") |
||||
log.Fatal("", "\t"+err.Error()) |
||||
} |
||||
} |
||||
} |
||||
|
||||
newCurPath = filepath.Join(newGoPathSrc, pkgName) |
||||
log.Log("Linking %s", pkgName) |
||||
err = autoLink(curPath, newCurPath) |
||||
if err != nil { |
||||
log.Error("", "Fail to make link:") |
||||
log.Fatal("", "\t"+err.Error()) |
||||
} |
||||
} |
@ -0,0 +1,13 @@
|
||||
//
|
||||
// +build !windows
|
||||
|
||||
package cmd |
||||
|
||||
import ( |
||||
"os/exec" |
||||
) |
||||
|
||||
func makeLink(srcPath, destPath string) error { |
||||
cmd := exec.Command("ln", "-s", srcPath, destPath) |
||||
return cmd.Run() |
||||
} |
@ -0,0 +1,81 @@
|
||||
package cmd |
||||
|
||||
import ( |
||||
"os" |
||||
"os/exec" |
||||
"path/filepath" |
||||
"strings" |
||||
"syscall" |
||||
"unsafe" |
||||
|
||||
"github.com/Unknwon/com" |
||||
|
||||
"github.com/gpmgo/gopm/doc" |
||||
) |
||||
|
||||
func makeLink(srcPath, destPath string) error { |
||||
// Check if Windows version is XP.
|
||||
if getWindowsVersion() >= 6 { |
||||
cmd := exec.Command("cmd", "/c", "mklink", "/j", destPath, srcPath) |
||||
return cmd.Run() |
||||
} |
||||
|
||||
// XP.
|
||||
isWindowsXP = true |
||||
// if both are ntfs file system
|
||||
if volumnType(srcPath) == "NTFS" && volumnType(destPath) == "NTFS" { |
||||
// if has junction command installed
|
||||
file, err := exec.LookPath("junction") |
||||
if err == nil { |
||||
path, _ := filepath.Abs(file) |
||||
if com.IsFile(path) { |
||||
cmd := exec.Command("cmd", "/c", "junction", destPath, srcPath) |
||||
return cmd.Run() |
||||
} |
||||
} |
||||
} |
||||
os.RemoveAll(destPath) |
||||
|
||||
return com.CopyDir(srcPath, destPath, func(filePath string) bool { |
||||
return strings.Contains(filePath, doc.VENDOR) |
||||
}) |
||||
} |
||||
|
||||
func volumnType(dir string) string { |
||||
pd := dir[:3] |
||||
dll := syscall.MustLoadDLL("kernel32.dll") |
||||
GetVolumeInformation := dll.MustFindProc("GetVolumeInformationW") |
||||
|
||||
var volumeNameSize uint32 = 260 |
||||
var nFileSystemNameSize, lpVolumeSerialNumber uint32 |
||||
var lpFileSystemFlags, lpMaximumComponentLength uint32 |
||||
var lpFileSystemNameBuffer, volumeName [260]byte |
||||
var ps *uint16 = syscall.StringToUTF16Ptr(pd) |
||||
|
||||
_, _, _ = GetVolumeInformation.Call(uintptr(unsafe.Pointer(ps)), |
||||
uintptr(unsafe.Pointer(&volumeName)), |
||||
uintptr(volumeNameSize), |
||||
uintptr(unsafe.Pointer(&lpVolumeSerialNumber)), |
||||
uintptr(unsafe.Pointer(&lpMaximumComponentLength)), |
||||
uintptr(unsafe.Pointer(&lpFileSystemFlags)), |
||||
uintptr(unsafe.Pointer(&lpFileSystemNameBuffer)), |
||||
uintptr(unsafe.Pointer(&nFileSystemNameSize)), 0) |
||||
|
||||
var bytes []byte |
||||
if lpFileSystemNameBuffer[6] == 0 { |
||||
bytes = []byte{lpFileSystemNameBuffer[0], lpFileSystemNameBuffer[2], |
||||
lpFileSystemNameBuffer[4]} |
||||
} else { |
||||
bytes = []byte{lpFileSystemNameBuffer[0], lpFileSystemNameBuffer[2], |
||||
lpFileSystemNameBuffer[4], lpFileSystemNameBuffer[6]} |
||||
} |
||||
|
||||
return string(bytes) |
||||
} |
||||
|
||||
func getWindowsVersion() int { |
||||
dll := syscall.MustLoadDLL("kernel32.dll") |
||||
p := dll.MustFindProc("GetVersion") |
||||
v, _, _ := p.Call() |
||||
return int(byte(v)) |
||||
} |
@ -0,0 +1,112 @@
|
||||
// Copyright 2013-2014 gopm authors.
|
||||
//
|
||||
// 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.
|
||||
|
||||
package cmd |
||||
|
||||
import ( |
||||
"path/filepath" |
||||
|
||||
"github.com/Unknwon/com" |
||||
"github.com/codegangsta/cli" |
||||
|
||||
"github.com/gpmgo/gopm/doc" |
||||
"github.com/gpmgo/gopm/log" |
||||
) |
||||
|
||||
var CmdInstall = cli.Command{ |
||||
Name: "install", |
||||
Usage: "link dependencies and go install", |
||||
Description: `Command install links dependencies according to gopmfile, |
||||
and execute 'go install' |
||||
|
||||
gopm install |
||||
gopm install <import path> |
||||
|
||||
If no argument is supplied, then gopmfile must be present`, |
||||
Action: runInstall, |
||||
Flags: []cli.Flag{ |
||||
cli.BoolFlag{"pkg, p", "only install non-main packages"}, |
||||
cli.BoolFlag{"verbose, v", "show process details"}, |
||||
}, |
||||
} |
||||
|
||||
func runInstall(ctx *cli.Context) { |
||||
setup(ctx) |
||||
|
||||
var target string |
||||
switch len(ctx.Args()) { |
||||
case 0: |
||||
if !com.IsFile(".gopmfile") { |
||||
break |
||||
} |
||||
|
||||
gf := doc.NewGopmfile(".") |
||||
target = gf.MustValue("target", "path") |
||||
case 1: |
||||
target = ctx.Args()[0] |
||||
default: |
||||
log.Fatal("install", "Too many arguments") |
||||
} |
||||
|
||||
// Get GOPATH.
|
||||
installGopath = com.GetGOPATHs()[0] |
||||
if com.IsDir(installGopath) { |
||||
isHasGopath = true |
||||
log.Log("Indicated GOPATH: %s", installGopath) |
||||
installGopath += "/src" |
||||
} else { |
||||
if ctx.Bool("gopath") { |
||||
log.Error("get", "Invalid GOPATH path") |
||||
log.Error("", "GOPATH does not exist or is not a directory:") |
||||
log.Error("", "\t"+installGopath) |
||||
log.Help("Try 'go help gopath' to get more information") |
||||
} else { |
||||
// It's OK that no GOPATH setting
|
||||
// when user does not specify to use.
|
||||
log.Warn("No GOPATH setting available") |
||||
} |
||||
} |
||||
|
||||
genNewGoPath(ctx, false) |
||||
|
||||
var installRepos []string |
||||
if ctx.Bool("pkg") { |
||||
curPath, _ := filepath.Abs(".") |
||||
installRepos = doc.GetAllImports([]string{curPath}, ".", ctx.Bool("example"), false) |
||||
} else { |
||||
if len(target) == 0 { |
||||
target = pkgName |
||||
} |
||||
|
||||
installRepos = []string{target} |
||||
} |
||||
|
||||
log.Trace("Installing...") |
||||
|
||||
for _, repo := range installRepos { |
||||
cmdArgs := []string{"go", "install"} |
||||
|
||||
if ctx.Bool("verbose") { |
||||
cmdArgs = append(cmdArgs, "-v") |
||||
} |
||||
cmdArgs = append(cmdArgs, repo) |
||||
err := execCmd(newGoPath, newCurPath, cmdArgs...) |
||||
if err != nil { |
||||
log.Error("install", "Fail to install program:") |
||||
log.Fatal("", "\t"+err.Error()) |
||||
} |
||||
} |
||||
|
||||
log.Success("SUCC", "install", "Command executed successfully!") |
||||
} |
@ -0,0 +1,58 @@
|
||||
// Copyright 2013 gopm authors.
|
||||
//
|
||||
// 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.
|
||||
|
||||
package cmd |
||||
|
||||
import ( |
||||
"github.com/Unknwon/com" |
||||
"github.com/codegangsta/cli" |
||||
|
||||
"github.com/gpmgo/gopm/log" |
||||
) |
||||
|
||||
var CmdRun = cli.Command{ |
||||
Name: "run", |
||||
Usage: "link dependencies and go run", |
||||
Description: `Command run links dependencies according to gopmfile, |
||||
and execute 'go run' |
||||
|
||||
gopm run <go run commands>`, |
||||
Action: runRun, |
||||
} |
||||
|
||||
func runRun(ctx *cli.Context) { |
||||
setup(ctx) |
||||
|
||||
// Get GOPATH.
|
||||
installGopath = com.GetGOPATHs()[0] |
||||
if com.IsDir(installGopath) { |
||||
isHasGopath = true |
||||
log.Log("Indicated GOPATH: %s", installGopath) |
||||
installGopath += "/src" |
||||
} |
||||
|
||||
genNewGoPath(ctx, false) |
||||
|
||||
log.Trace("Running...") |
||||
|
||||
cmdArgs := []string{"go", "run"} |
||||
cmdArgs = append(cmdArgs, ctx.Args()...) |
||||
err := execCmd(newGoPath, newCurPath, cmdArgs...) |
||||
if err != nil { |
||||
log.Error("run", "Fail to run program:") |
||||
log.Fatal("", "\t"+err.Error()) |
||||
} |
||||
|
||||
log.Success("SUCC", "run", "Command executed successfully!") |
||||
} |
@ -0,0 +1,112 @@
|
||||
// Copyright 2013 gopm authors.
|
||||
//
|
||||
// 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.
|
||||
|
||||
package cmd |
||||
|
||||
// import (
|
||||
// "encoding/json"
|
||||
// "fmt"
|
||||
// "io/ioutil"
|
||||
// "net/http"
|
||||
|
||||
// "github.com/Unknwon/com"
|
||||
// )
|
||||
|
||||
// var CmdSearch = &Command{
|
||||
// UsageLine: "search [keyword]",
|
||||
// Short: "search for package",
|
||||
// Long: `
|
||||
// search packages
|
||||
|
||||
// The search flags are:
|
||||
|
||||
// -e
|
||||
// search extactly, you should input an exactly package name as keyword
|
||||
// `,
|
||||
// }
|
||||
|
||||
// func init() {
|
||||
// CmdSearch.Run = runSearch
|
||||
// CmdSearch.Flags = map[string]bool{
|
||||
// "-e": false,
|
||||
// }
|
||||
// }
|
||||
|
||||
// func printSearchPrompt(flag string) {
|
||||
// switch flag {
|
||||
// case "-e":
|
||||
// com.ColorLog("[INFO] You enabled exactly search.\n")
|
||||
// }
|
||||
// }
|
||||
|
||||
// // search packages
|
||||
// func runSearch(cmd *Command, args []string) {
|
||||
|
||||
// // Check length of arguments.
|
||||
// if len(args) < 1 {
|
||||
// com.ColorLog("[ERROR] Please input package's keyword.\n")
|
||||
// return
|
||||
// }
|
||||
|
||||
// var host, port string
|
||||
// host = "localhost"
|
||||
// port = "8991"
|
||||
|
||||
// if cmd.Flags["-e"] {
|
||||
// search(host, port, args[0], true)
|
||||
// } else {
|
||||
// search(host, port, args[0], false)
|
||||
// }
|
||||
// }
|
||||
|
||||
// type searchRes struct {
|
||||
// Pkg string
|
||||
// Desc string
|
||||
// }
|
||||
|
||||
// /*
|
||||
// request local or remote search service to find packages according to keyword inputed
|
||||
// */
|
||||
// func search(host, port, keyword string, isExactly bool) {
|
||||
// url := fmt.Sprintf("http://%v:%v/search?%v", host, port, keyword)
|
||||
// if isExactly {
|
||||
// url = fmt.Sprintf("http://%v:%v/searche?%v", host, port, keyword)
|
||||
// }
|
||||
// resp, err := http.Get(url)
|
||||
// if err != nil {
|
||||
// com.ColorLog(err.Error())
|
||||
// return
|
||||
// }
|
||||
// defer resp.Body.Close()
|
||||
|
||||
// if resp.StatusCode == 200 {
|
||||
// contents, err := ioutil.ReadAll(resp.Body)
|
||||
// if err != nil {
|
||||
// com.ColorLog(err.Error())
|
||||
// return
|
||||
// }
|
||||
|
||||
// pkgs := make([]searchRes, 0)
|
||||
// err = json.Unmarshal(contents, &pkgs)
|
||||
// if err != nil {
|
||||
// com.ColorLog(err.Error())
|
||||
// return
|
||||
// }
|
||||
// for i, pkg := range pkgs {
|
||||
// fmt.Println(i+1, pkg.Pkg, "\t", pkg.Desc)
|
||||
// }
|
||||
// } else {
|
||||
// com.ColorLog(resp.Status)
|
||||
// }
|
||||
// }
|
@ -0,0 +1,552 @@
|
||||
// Copyright 2013 gopm authors.
|
||||
//
|
||||
// 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.
|
||||
|
||||
package cmd |
||||
|
||||
// import (
|
||||
// "errors"
|
||||
// "fmt"
|
||||
// "github.com/Unknwon/com"
|
||||
// "github.com/gpmgo/gopm/doc"
|
||||
// "github.com/syndtr/goleveldb/leveldb"
|
||||
// "github.com/syndtr/goleveldb/leveldb/opt"
|
||||
// "io/ioutil"
|
||||
// "net/http"
|
||||
// "net/url"
|
||||
// "os"
|
||||
// "os/exec"
|
||||
// "path/filepath"
|
||||
// "strconv"
|
||||
// "strings"
|
||||
// "time"
|
||||
// )
|
||||
|
||||
// var (
|
||||
// dbDir = "~/.gopm/db"
|
||||
// )
|
||||
|
||||
// const (
|
||||
// STOP = iota
|
||||
// LOCALRUN
|
||||
// RUNNING
|
||||
// )
|
||||
|
||||
// var CmdServe = &Command{
|
||||
// UsageLine: "serve [:port]",
|
||||
// Short: "serve for package search",
|
||||
// Long: `
|
||||
// serve provide a web service to search packages, download packages
|
||||
|
||||
// The serve flags are:
|
||||
|
||||
// -l
|
||||
// only service for localhost ip
|
||||
// `,
|
||||
// }
|
||||
|
||||
// func init() {
|
||||
// CmdServe.Run = runServe
|
||||
// CmdServe.Flags = map[string]bool{
|
||||
// "-l": false,
|
||||
// }
|
||||
// }
|
||||
|
||||
// func printServePrompt(flag string) {
|
||||
// switch flag {
|
||||
// case "-l":
|
||||
// com.ColorLog("[INFO] You enabled start a service only localhost.\n")
|
||||
// }
|
||||
// }
|
||||
|
||||
// // Not implemented
|
||||
// func autoPort() string {
|
||||
// return "8991"
|
||||
// }
|
||||
|
||||
// func exePath() (string, error) {
|
||||
// file, err := exec.LookPath(os.Args[0])
|
||||
// if err != nil {
|
||||
// return "", err
|
||||
// }
|
||||
|
||||
// return filepath.Abs(file)
|
||||
// }
|
||||
|
||||
// // search packages
|
||||
// func runServe(cmd *Command, args []string) {
|
||||
// // Check flags.
|
||||
// num := checkFlags(cmd.Flags, args, printServePrompt)
|
||||
// if num == -1 {
|
||||
// return
|
||||
// }
|
||||
// args = args[num:]
|
||||
|
||||
// var listen string
|
||||
// var port string
|
||||
// if cmd.Flags["-l"] {
|
||||
// listen += "127.0.0.1"
|
||||
// port = autoPort()
|
||||
// } else {
|
||||
// listen += "0.0.0.0"
|
||||
// port = "8991"
|
||||
// }
|
||||
|
||||
// // Check length of arguments.
|
||||
// if len(args) >= 1 {
|
||||
// port = args[0]
|
||||
// }
|
||||
|
||||
// err := startService(listen, port)
|
||||
// if err != nil {
|
||||
// com.ColorLog("[ERRO] %v\n", err)
|
||||
// }
|
||||
// }
|
||||
|
||||
// func splitWord(word string, res *map[string]bool) {
|
||||
// for i, _ := range word {
|
||||
// for j, _ := range word[i:] {
|
||||
// w := word[i : i+j+1]
|
||||
// (*res)[w] = true
|
||||
// }
|
||||
// }
|
||||
// return
|
||||
// }
|
||||
|
||||
// func splitPkgName(pkgName string) (res map[string]bool) {
|
||||
// //var src string
|
||||
// ps := strings.Split(pkgName, "/")
|
||||
// if len(ps) > 1 {
|
||||
// ps = ps[1:]
|
||||
// }
|
||||
|
||||
// res = make(map[string]bool)
|
||||
// res[strings.Join(ps, "/")] = true
|
||||
// for _, w := range ps {
|
||||
// splitWord(w, &res)
|
||||
// }
|
||||
// return
|
||||
// }
|
||||
|
||||
// func splitSynopsis(synopsis string) map[string]bool {
|
||||
// res := make(map[string]bool)
|
||||
// ss := strings.Fields(synopsis)
|
||||
// for _, s := range ss {
|
||||
// res[s] = true
|
||||
// }
|
||||
// return res
|
||||
// }
|
||||
|
||||
// var (
|
||||
// ro *opt.ReadOptions = &opt.ReadOptions{}
|
||||
// wo *opt.WriteOptions = &opt.WriteOptions{}
|
||||
// )
|
||||
|
||||
// func dbGet(key string) (string, error) {
|
||||
// v, err := db.Get([]byte(key), ro)
|
||||
// return string(v), err
|
||||
// }
|
||||
|
||||
// func dbPut(key string, value string) error {
|
||||
// //fmt.Println("put ", key, ": ", value)
|
||||
// return db.Put([]byte(key), []byte(value), wo)
|
||||
// }
|
||||
|
||||
// func batchPut(batch *leveldb.Batch, key string, value string) error {
|
||||
// //fmt.Println("put ", key, ": ", value)
|
||||
// batch.Put([]byte(key), []byte(value))
|
||||
// return nil
|
||||
// }
|
||||
|
||||
// func getServeHost() string {
|
||||
// return "localhost"
|
||||
// }
|
||||
|
||||
// func getServePort() string {
|
||||
// return "8991"
|
||||
// }
|
||||
|
||||
// // for exernal of serve to add node to db
|
||||
// func saveNode(nod *doc.Node) error {
|
||||
// urlPath := fmt.Sprintf("http://%v:%v/add", getServeHost(), getServePort())
|
||||
// resp, err := http.PostForm(urlPath,
|
||||
// url.Values{"importPath": {nod.ImportPath},
|
||||
// "synopsis": {nod.Synopsis},
|
||||
// "downloadURL": {nod.DownloadURL},
|
||||
// "isGetDeps": {strconv.FormatBool(nod.IsGetDeps)},
|
||||
// "type": {nod.Type},
|
||||
// "value": {nod.Value}})
|
||||
|
||||
// if err != nil {
|
||||
// com.ColorLog("[ERRO] Fail to save node[ %s ]\n", err)
|
||||
// return err
|
||||
// }
|
||||
// defer resp.Body.Close()
|
||||
|
||||
// if resp.StatusCode == 200 {
|
||||
// return nil
|
||||
// }
|
||||
// return errors.New("save node failed with " + resp.Status)
|
||||
// }
|
||||
|
||||
// // for inetrnal of serve to add node to db
|
||||
// func addNode(nod *doc.Node) error {
|
||||
// batch := new(leveldb.Batch)
|
||||
// strLastId, err := dbGet("lastId")
|
||||
// if err != nil {
|
||||
// if err == leveldb.ErrNotFound {
|
||||
// strLastId = "0"
|
||||
// err = batchPut(batch, "lastId", strLastId)
|
||||
// } else {
|
||||
// return err
|
||||
// }
|
||||
// }
|
||||
// if err != nil {
|
||||
// return err
|
||||
// }
|
||||
|
||||
// lastId, err := strconv.ParseInt(strLastId, 0, 64)
|
||||
// if err != nil {
|
||||
// return err
|
||||
// }
|
||||
|
||||
// nodKey := fmt.Sprintf("index:%v", nod.ImportPath)
|
||||
|
||||
// id, err := dbGet(nodKey)
|
||||
// if err != nil {
|
||||
// if err == leveldb.ErrNotFound {
|
||||
// id = fmt.Sprintf("%v", lastId+1)
|
||||
// err = batchPut(batch, "lastId", id)
|
||||
// if err == nil {
|
||||
// err = batchPut(batch, nodKey, id)
|
||||
// }
|
||||
// if err == nil {
|
||||
// err = batchPut(batch, "pkg:"+id, nod.ImportPath)
|
||||
// }
|
||||
// if err == nil {
|
||||
// err = batchPut(batch, "desc:"+id, nod.Synopsis)
|
||||
// }
|
||||
// if err == nil {
|
||||
// err = batchPut(batch, "down:"+id, nod.DownloadURL)
|
||||
// }
|
||||
// if err == nil {
|
||||
// err = batchPut(batch, "deps:"+id, strconv.FormatBool(nod.IsGetDeps))
|
||||
// }
|
||||
|
||||
// // save totals
|
||||
// total, err := dbGet("total")
|
||||
// if err != nil {
|
||||
// if err == leveldb.ErrNotFound {
|
||||
// total = "1"
|
||||
// } else {
|
||||
// return err
|
||||
// }
|
||||
// } else {
|
||||
// totalInt, err := strconv.ParseInt(total, 0, 64)
|
||||
// if err != nil {
|
||||
// return err
|
||||
// }
|
||||
// totalInt = totalInt + 1
|
||||
// total = fmt.Sprintf("%v", totalInt)
|
||||
// }
|
||||
|
||||
// err = batchPut(batch, "total", total)
|
||||
// } else {
|
||||
// return err
|
||||
// }
|
||||
// }
|
||||
|
||||
// if err != nil {
|
||||
// return err
|
||||
// }
|
||||
|
||||
// // save vers
|
||||
// vers, err := dbGet("ver:" + id)
|
||||
// needSplit := (err == leveldb.ErrNotFound)
|
||||
// if err != nil {
|
||||
// if err != leveldb.ErrNotFound {
|
||||
// return err
|
||||
// }
|
||||
// } else {
|
||||
// return nil
|
||||
// }
|
||||
|
||||
// if vers == "" {
|
||||
// //fmt.Println(nod)
|
||||
// vers = nod.VerString()
|
||||
// } else {
|
||||
// if !strings.Contains(vers, nod.VerString()) {
|
||||
// vers = vers + "," + nod.VerString()
|
||||
// } else {
|
||||
// return nil
|
||||
// }
|
||||
// }
|
||||
|
||||
// err = batchPut(batch, "ver:"+id, vers)
|
||||
// if err != nil {
|
||||
// return err
|
||||
// }
|
||||
|
||||
// if !needSplit {
|
||||
// return nil
|
||||
// }
|
||||
|
||||
// // indexing package name
|
||||
// keys := splitPkgName(nod.ImportPath)
|
||||
// for key, _ := range keys {
|
||||
// err = batchPut(batch, fmt.Sprintf("key:%v:%v", strings.ToLower(key), id), "")
|
||||
// if err != nil {
|
||||
// return err
|
||||
// }
|
||||
// }
|
||||
|
||||
// if nod.Synopsis != "" {
|
||||
// fields := splitSynopsis(nod.Synopsis)
|
||||
// for field, _ := range fields {
|
||||
// err = batchPut(batch, fmt.Sprintf("key:%v:%v", strings.ToLower(field), id), "")
|
||||
// if err != nil {
|
||||
// return err
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// return db.Write(batch, wo)
|
||||
// }
|
||||
|
||||
// func rmPkg(nod *doc.Node) {
|
||||
|
||||
// }
|
||||
|
||||
// var db *leveldb.DB
|
||||
|
||||
// // service should be run
|
||||
// func AutoRun() error {
|
||||
// s, _, _ := runningStatus()
|
||||
// if s == STOP {
|
||||
// // current path
|
||||
// curPath, err := os.Getwd()
|
||||
// if err != nil {
|
||||
// return err
|
||||
// }
|
||||
|
||||
// attr := &os.ProcAttr{
|
||||
// Dir: curPath,
|
||||
// Env: os.Environ(),
|
||||
// //Files: []*os.File{nil, nil, nil},
|
||||
// Files: []*os.File{os.Stdin, os.Stdout, os.Stderr},
|
||||
// }
|
||||
|
||||
// p, err := exePath()
|
||||
// if err != nil {
|
||||
// return err
|
||||
// }
|
||||
|
||||
// //com.ColorLog("[INFO] now is starting search daemon ...\n")
|
||||
// _, err = os.StartProcess(p, []string{"gopm", "serve", "-l"}, attr)
|
||||
// if err != nil {
|
||||
// return err
|
||||
// }
|
||||
// time.Sleep(time.Second)
|
||||
// }
|
||||
// return nil
|
||||
// }
|
||||
|
||||
// func runningStatus() (int, int, int) {
|
||||
// pFile, err := getPidPath()
|
||||
// if err != nil {
|
||||
// return STOP, 0, 0
|
||||
// }
|
||||
|
||||
// contentByte, err := ioutil.ReadFile(pFile)
|
||||
// if err != nil {
|
||||
// return STOP, 0, 0
|
||||
// }
|
||||
// content := string(contentByte)
|
||||
// if len(content) < 0 || !strings.Contains(content, ",") {
|
||||
// return STOP, 0, 0
|
||||
// }
|
||||
// cs := strings.Split(string(content), ",")
|
||||
// if len(cs) != 3 {
|
||||
// return STOP, 0, 0
|
||||
// }
|
||||
// status, err := strconv.Atoi(cs[0])
|
||||
// if err != nil {
|
||||
// return STOP, 0, 0
|
||||
// }
|
||||
// if status < STOP || status > RUNNING {
|
||||
// return STOP, 0, 0
|
||||
// }
|
||||
// pid, err := strconv.Atoi(cs[1])
|
||||
// if err != nil {
|
||||
// return STOP, 0, 0
|
||||
// }
|
||||
|
||||
// _, err = os.FindProcess(pid)
|
||||
// if err != nil {
|
||||
// return STOP, 0, 0
|
||||
// }
|
||||
|
||||
// port, err := strconv.Atoi(cs[2])
|
||||
// if err != nil {
|
||||
// return STOP, 0, 0
|
||||
// }
|
||||
|
||||
// return status, pid, port
|
||||
// }
|
||||
|
||||
// func getPidPath() (string, error) {
|
||||
// homeDir, err := com.HomeDir()
|
||||
// if err != nil {
|
||||
// return "", err
|
||||
// }
|
||||
|
||||
// pFile := strings.Replace("~/.gopm/var/", "~", homeDir, -1)
|
||||
// os.MkdirAll(pFile, os.ModePerm)
|
||||
// return pFile + "pid", nil
|
||||
// }
|
||||
|
||||
// func startService(listen, port string) error {
|
||||
// homeDir, err := com.HomeDir()
|
||||
// if err != nil {
|
||||
// return err
|
||||
// }
|
||||
|
||||
// pFile, err := getPidPath()
|
||||
// if err != nil {
|
||||
// return err
|
||||
// }
|
||||
|
||||
// f, err := os.OpenFile(pFile, os.O_RDWR|os.O_CREATE, 0700)
|
||||
// if err != nil {
|
||||
// return err
|
||||
// }
|
||||
// defer f.Close()
|
||||
// _, err = f.WriteString(fmt.Sprintf("%v,%v,%v", RUNNING, os.Getpid(), port))
|
||||
// if err != nil {
|
||||
// return err
|
||||
// }
|
||||
|
||||
// dbDir = strings.Replace(dbDir, "~", homeDir, -1)
|
||||
|
||||
// db, err = leveldb.OpenFile(dbDir, nil)
|
||||
// if err != nil {
|
||||
// return err
|
||||
// }
|
||||
// defer db.Close()
|
||||
|
||||
// // these handlers should only access by localhost
|
||||
// http.HandleFunc("/add", addHandler)
|
||||
// http.HandleFunc("/rm", rmHandler)
|
||||
|
||||
// // these handlers can be accessed according listen's ip
|
||||
// http.HandleFunc("/search", searchHandler)
|
||||
// http.HandleFunc("/searche", searcheHandler)
|
||||
// http.ListenAndServe(listen+":"+port, nil)
|
||||
// return nil
|
||||
// }
|
||||
|
||||
// func searchHandler(w http.ResponseWriter, r *http.Request) {
|
||||
// r.ParseForm()
|
||||
// ids := make(map[string]bool)
|
||||
// for key, _ := range r.Form {
|
||||
// iter := db.NewIterator(ro)
|
||||
// rkey := fmt.Sprintf("key:%v:", strings.ToLower(key))
|
||||
// if iter.Seek([]byte(rkey)) {
|
||||
// k := iter.Key()
|
||||
// if !strings.HasPrefix(string(k), rkey) {
|
||||
// break
|
||||
// } else {
|
||||
// ids[string(k)] = true
|
||||
// }
|
||||
// }
|
||||
// for iter.Next() {
|
||||
// k := iter.Key()
|
||||
// if !strings.HasPrefix(string(k), rkey) {
|
||||
// break
|
||||
// }
|
||||
// ids[string(k)] = true
|
||||
// }
|
||||
// }
|
||||
|
||||
// pkgs := make([]string, 0)
|
||||
|
||||
// for id, _ := range ids {
|
||||
// idkeys := strings.SplitN(id, ":", -1)
|
||||
// rId := idkeys[len(idkeys)-1]
|
||||
// //fmt.Println(rId)
|
||||
// pkg, err := dbGet(fmt.Sprintf("pkg:%v", rId))
|
||||
// if err != nil {
|
||||
// com.ColorLog(err.Error())
|
||||
// continue
|
||||
// }
|
||||
// desc, err := dbGet(fmt.Sprintf("desc:%v", rId))
|
||||
// if err != nil {
|
||||
// com.ColorLog(err.Error())
|
||||
// continue
|
||||
// }
|
||||
// pkgs = append(pkgs, fmt.Sprintf(`{"pkg":"%v", "desc":"%v"}`, pkg, desc))
|
||||
// }
|
||||
|
||||
// w.Write([]byte("[" + strings.Join(pkgs, ", ") + "]"))
|
||||
// }
|
||||
|
||||
// func searcheHandler(w http.ResponseWriter, r *http.Request) {
|
||||
// //if r.Method == "POST" {
|
||||
// r.ParseForm()
|
||||
// pkgs := make([]string, 0)
|
||||
// for key, _ := range r.Form {
|
||||
// rId, err := dbGet("index:" + key)
|
||||
// if err != nil {
|
||||
// com.ColorLog(err.Error())
|
||||
// continue
|
||||
// }
|
||||
|
||||
// desc, err := dbGet(fmt.Sprintf("desc:%v", rId))
|
||||
// if err != nil {
|
||||
// com.ColorLog(err.Error())
|
||||
// continue
|
||||
// }
|
||||
|
||||
// pkgs = append(pkgs, fmt.Sprintf(`{"pkg":"%v", "desc":"%v"}`, key, desc))
|
||||
// }
|
||||
|
||||
// w.Write([]byte("[" + strings.Join(pkgs, ", ") + "]"))
|
||||
// //}
|
||||
// }
|
||||
|
||||
// func addHandler(w http.ResponseWriter, r *http.Request) {
|
||||
// //if r.Method == "POST" {
|
||||
// r.ParseForm()
|
||||
|
||||
// nod := new(doc.Node)
|
||||
// nod.ImportPath = r.FormValue("importPath")
|
||||
// nod.Synopsis = r.FormValue("synopsis")
|
||||
// nod.DownloadURL = r.FormValue("downloadURL")
|
||||
// isGetDeps, err := strconv.ParseBool(r.FormValue("isGetDeps"))
|
||||
// if err != nil {
|
||||
// com.ColorLog("[ERRO] SEVER: Cannot get deps")
|
||||
// }
|
||||
// nod.IsGetDeps = isGetDeps
|
||||
// nod.Type = r.FormValue("type")
|
||||
// nod.Value = r.FormValue("value")
|
||||
|
||||
// err = addNode(nod)
|
||||
// if err != nil {
|
||||
// com.ColorLog("[ERRO] SEVER: Cannot add node[ %s ]\n", err)
|
||||
// }
|
||||
// //}
|
||||
// }
|
||||
|
||||
// func rmHandler(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
// }
|
@ -0,0 +1,213 @@
|
||||
// Copyright 2013 gopm authors.
|
||||
//
|
||||
// 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.
|
||||
|
||||
package cmd |
||||
|
||||
// func getService(pkgName string) Service {
|
||||
// for _, service := range services {
|
||||
// if service.HasPkg(pkgName) {
|
||||
// return service
|
||||
// }
|
||||
// }
|
||||
// return nil
|
||||
// }
|
||||
|
||||
// type Service interface {
|
||||
// PkgUrl(pkg *Pkg) string
|
||||
// HasPkg(pkgName string) bool
|
||||
// PkgExt() string
|
||||
// }
|
||||
|
||||
//type Pkg struct {
|
||||
// Name string
|
||||
// Ver string
|
||||
// VerId string
|
||||
//}
|
||||
|
||||
// func NewPkg(pkgName string, ver string) *Pkg {
|
||||
// vers := strings.Split(ver, ":")
|
||||
// if len(vers) > 2 {
|
||||
// return nil
|
||||
// }
|
||||
|
||||
// var verId string
|
||||
// if len(vers) == 2 {
|
||||
// verId = vers[1]
|
||||
// }
|
||||
|
||||
// if len(vers) == 1 {
|
||||
// vers[0] = TRUNK
|
||||
// }
|
||||
|
||||
// service := getService(pkgName)
|
||||
// if service == nil {
|
||||
// return nil
|
||||
// }
|
||||
|
||||
// return &Pkg{service, pkgName, vers[0], verId}
|
||||
// }
|
||||
|
||||
// func (p *Pkg) VerSimpleString() string {
|
||||
// if p.VerId != "" {
|
||||
// return p.VerId
|
||||
// }
|
||||
// return p.Ver
|
||||
// }
|
||||
|
||||
// func (p *Pkg) Url() string {
|
||||
// return p.Service.PkgUrl(p)
|
||||
// }
|
||||
|
||||
// func (p *Pkg) FileName() string {
|
||||
// return fmt.Sprintf("%v.%v", p.VerSimpleString(), p.Service.PkgExt())
|
||||
// }
|
||||
|
||||
// // github repository
|
||||
// type GithubService struct {
|
||||
// }
|
||||
|
||||
// func (s *GithubService) PkgUrl(pkg *Pkg) string {
|
||||
// var verPath string
|
||||
// if pkg.Ver == TRUNK {
|
||||
// verPath = "master"
|
||||
// } else {
|
||||
// verPath = pkg.VerId
|
||||
// }
|
||||
// return fmt.Sprintf("https://%v/archive/%v.zip", pkg.Name, verPath)
|
||||
// }
|
||||
|
||||
// func (s *GithubService) HasPkg(pkgName string) bool {
|
||||
// return strings.HasPrefix(pkgName, "github.com")
|
||||
// }
|
||||
|
||||
// func (s *GithubService) PkgExt() string {
|
||||
// return "zip"
|
||||
// }
|
||||
|
||||
// // git osc repos
|
||||
// type GitOscService struct {
|
||||
// }
|
||||
|
||||
// func (s *GitOscService) PkgUrl(pkg *Pkg) string {
|
||||
// var verPath string
|
||||
// if pkg.Ver == TRUNK {
|
||||
// verPath = "master"
|
||||
// } else {
|
||||
// verPath = pkg.VerId
|
||||
// }
|
||||
// return fmt.Sprintf("https://%v/repository/archive?ref=%v", pkg.Name, verPath)
|
||||
// }
|
||||
|
||||
// func (s *GitOscService) HasPkg(pkgName string) bool {
|
||||
// return strings.HasPrefix(pkgName, "git.oschina.net")
|
||||
// }
|
||||
|
||||
// func (s *GitOscService) PkgExt() string {
|
||||
// return "zip"
|
||||
// }
|
||||
|
||||
// // bitbucket.org
|
||||
// type BitBucketService struct {
|
||||
// }
|
||||
|
||||
// func (s *BitBucketService) PkgUrl(pkg *Pkg) string {
|
||||
// var verPath string
|
||||
// if pkg.Ver == TRUNK {
|
||||
// verPath = "default"
|
||||
// } else {
|
||||
// verPath = pkg.VerId
|
||||
// }
|
||||
|
||||
// return fmt.Sprintf("https://%v/get/%v.zip", pkg.Name, verPath)
|
||||
// }
|
||||
|
||||
// func (s *BitBucketService) HasPkg(pkgName string) bool {
|
||||
// return strings.HasPrefix(pkgName, "bitbucket.org")
|
||||
// }
|
||||
|
||||
// func (s *BitBucketService) PkgExt() string {
|
||||
// return "zip"
|
||||
// }
|
||||
|
||||
// type GitCafeService struct {
|
||||
// }
|
||||
|
||||
// func (s *GitCafeService) PkgUrl(pkg *Pkg) string {
|
||||
// var verPath string
|
||||
// if pkg.Ver == TRUNK {
|
||||
// verPath = "master"
|
||||
// } else {
|
||||
// verPath = pkg.VerId
|
||||
// }
|
||||
|
||||
// return fmt.Sprintf("https://%v/tarball/%v", pkg.Name, verPath)
|
||||
// }
|
||||
|
||||
// func (s *GitCafeService) HasPkg(pkgName string) bool {
|
||||
// return strings.HasPrefix(pkgName, "gitcafe.com")
|
||||
// }
|
||||
|
||||
// func (s *GitCafeService) PkgExt() string {
|
||||
// return "tar.gz"
|
||||
// }
|
||||
|
||||
// // git lab repos, not completed
|
||||
// type GitLabService struct {
|
||||
// DomainOrIp string
|
||||
// Username string
|
||||
// Passwd string
|
||||
// PrivateKey string
|
||||
// }
|
||||
|
||||
// func (s *GitLabService) PkgUrl(pkg *Pkg) string {
|
||||
// var verPath string
|
||||
// if pkg.Ver == TRUNK {
|
||||
// verPath = "master"
|
||||
// } else {
|
||||
// verPath = pkg.VerId
|
||||
// }
|
||||
|
||||
// return fmt.Sprintf("https://%v/repository/archive/%v", pkg.Name, verPath)
|
||||
// }
|
||||
|
||||
// func (s *GitLabService) HasPkg(pkgName string) bool {
|
||||
// return strings.HasPrefix(pkgName, s.DomainOrIp)
|
||||
// }
|
||||
|
||||
// func (s *GitLabService) PkgExt() string {
|
||||
// return "tar.gz"
|
||||
// }
|
||||
|
||||
// // code.csdn.net
|
||||
// type CodeCSDNService struct {
|
||||
// }
|
||||
|
||||
// func (s *CodeCSDNService) PkgUrl(pkg *Pkg) string {
|
||||
// var verPath string
|
||||
// if pkg.Ver == TRUNK {
|
||||
// verPath = "master"
|
||||
// } else {
|
||||
// verPath = pkg.VerId
|
||||
// }
|
||||
|
||||
// return fmt.Sprintf("https://%v/repository/archive?ref=%v", pkg.Name, verPath)
|
||||
// }
|
||||
|
||||
// func (s *CodeCSDNService) HasPkg(pkgName string) bool {
|
||||
// return strings.HasPrefix(pkgName, "code.csdn.net")
|
||||
// }
|
||||
|
||||
// func (s *CodeCSDNService) PkgExt() string {
|
||||
// return "zip"
|
||||
// }
|
@ -0,0 +1,47 @@
|
||||
// Copyright 2013 gopm authors.
|
||||
//
|
||||
// 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.
|
||||
|
||||
package cmd |
||||
|
||||
import ( |
||||
"github.com/codegangsta/cli" |
||||
|
||||
"github.com/gpmgo/gopm/log" |
||||
) |
||||
|
||||
var CmdTest = cli.Command{ |
||||
Name: "test", |
||||
Usage: "link dependencies and go test", |
||||
Description: `Command test links dependencies according to gopmfile, |
||||
and execute 'go test' |
||||
|
||||
gopm test <go test commands>`, |
||||
Action: runTest, |
||||
} |
||||
|
||||
func runTest(ctx *cli.Context) { |
||||
genNewGoPath(ctx, true) |
||||
|
||||
log.Trace("Testing...") |
||||
|
||||
cmdArgs := []string{"go", "test"} |
||||
cmdArgs = append(cmdArgs, ctx.Args()...) |
||||
err := execCmd(newGoPath, newCurPath, cmdArgs...) |
||||
if err != nil { |
||||
log.Error("Test", "Fail to test program") |
||||
log.Fatal("", err.Error()) |
||||
} |
||||
|
||||
log.Success("SUCC", "Test", "Command execute successfully!") |
||||
} |
@ -0,0 +1,215 @@
|
||||
// Copyright 2013 gopm authors.
|
||||
//
|
||||
// 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.
|
||||
|
||||
package cmd |
||||
|
||||
import ( |
||||
"encoding/json" |
||||
"fmt" |
||||
"net/http" |
||||
"os" |
||||
"os/exec" |
||||
"path" |
||||
"path/filepath" |
||||
"runtime" |
||||
|
||||
"github.com/Unknwon/com" |
||||
"github.com/codegangsta/cli" |
||||
|
||||
"github.com/gpmgo/gopm/doc" |
||||
"github.com/gpmgo/gopm/log" |
||||
) |
||||
|
||||
var CmdUpdate = cli.Command{ |
||||
Name: "update", |
||||
Usage: "check and update gopm resources including itself", |
||||
Description: `Command update checks updates of resources and gopm itself. |
||||
|
||||
gopm update |
||||
|
||||
Resources will be updated automatically after executed this command, |
||||
but you have to confirm before updaing gopm itself.`, |
||||
Action: runUpdate, |
||||
Flags: []cli.Flag{ |
||||
cli.BoolFlag{"verbose, v", "show process details"}, |
||||
}, |
||||
} |
||||
|
||||
func exePath() string { |
||||
file, err := exec.LookPath(os.Args[0]) |
||||
if err != nil { |
||||
log.Error("Update", "Fail to execute exec.LookPath") |
||||
log.Fatal("", err.Error()) |
||||
} |
||||
path, err := filepath.Abs(file) |
||||
if err != nil { |
||||
log.Error("Update", "Fail to get absolutely path") |
||||
log.Fatal("", err.Error()) |
||||
} |
||||
return path |
||||
} |
||||
|
||||
type version struct { |
||||
Gopm int |
||||
PackageNameList int `json:"package_name_list"` |
||||
} |
||||
|
||||
func runUpdate(ctx *cli.Context) { |
||||
setup(ctx) |
||||
|
||||
isAnythingUpdated := false |
||||
// Load local version info.
|
||||
localVerInfo := loadLocalVerInfo() |
||||
|
||||
// Get remote version info.
|
||||
var remoteVerInfo version |
||||
if err := com.HttpGetJSON(http.DefaultClient, "http://gopm.io/VERSION.json", &remoteVerInfo); err != nil { |
||||
log.Error("Update", "Fail to fetch VERSION.json") |
||||
log.Fatal("", err.Error()) |
||||
} |
||||
|
||||
// Package name list.
|
||||
if remoteVerInfo.PackageNameList > localVerInfo.PackageNameList { |
||||
log.Log("Updating pkgname.list...%v > %v", |
||||
localVerInfo.PackageNameList, remoteVerInfo.PackageNameList) |
||||
data, err := com.HttpGetBytes(http.DefaultClient, "https://raw2.github.com/gpmgo/docs/master/pkgname.list", nil) |
||||
if err != nil { |
||||
log.Error("Update", "Fail to update pkgname.list") |
||||
log.Fatal("", err.Error()) |
||||
} |
||||
_, err = com.SaveFile(path.Join(doc.HomeDir, doc.PKG_NAME_LIST_PATH), data) |
||||
if err != nil { |
||||
log.Error("Update", "Fail to save pkgname.list") |
||||
log.Fatal("", err.Error()) |
||||
} |
||||
log.Log("Update pkgname.list to %v succeed!", remoteVerInfo.PackageNameList) |
||||
isAnythingUpdated = true |
||||
} |
||||
|
||||
// Gopm.
|
||||
if remoteVerInfo.Gopm > localVerInfo.Gopm { |
||||
log.Log("Updating gopm...%v > %v", |
||||
localVerInfo.Gopm, remoteVerInfo.Gopm) |
||||
installRepoPath = doc.HomeDir + "/repos" |
||||
|
||||
tmpDirPath := filepath.Join(doc.HomeDir, "temp") |
||||
tmpBinPath := filepath.Join(tmpDirPath, "gopm") |
||||
if runtime.GOOS == "windows" { |
||||
tmpBinPath += ".exe" |
||||
} |
||||
|
||||
os.MkdirAll(tmpDirPath, os.ModePerm) |
||||
os.Remove(tmpBinPath) |
||||
|
||||
// Fetch code.
|
||||
args := []string{"bin", "-u", "-d"} |
||||
if ctx.Bool("verbose") { |
||||
args = append(args, "-v") |
||||
} |
||||
args = append(args, []string{"github.com/gpmgo/gopm", tmpDirPath}...) |
||||
stdout, stderr, err := com.ExecCmd("gopm", args...) |
||||
if err != nil { |
||||
log.Error("Update", "Fail to execute 'gopm bin -u -d github.com/gpmgo/gopm "+tmpDirPath+"'") |
||||
log.Fatal("", err.Error()) |
||||
} |
||||
if len(stderr) > 0 { |
||||
fmt.Print(stderr) |
||||
} |
||||
if len(stdout) > 0 { |
||||
fmt.Print(stdout) |
||||
} |
||||
|
||||
// Check if previous steps were successful.
|
||||
if !com.IsExist(tmpBinPath) { |
||||
log.Error("Update", "Fail to continue command") |
||||
log.Fatal("", "Previous steps weren't successful, no binary produced") |
||||
} |
||||
|
||||
movePath := exePath() |
||||
log.Log("New binary will be replaced for %s", movePath) |
||||
// Move binary to given directory.
|
||||
if runtime.GOOS != "windows" { |
||||
err := os.Rename(tmpBinPath, movePath) |
||||
if err != nil { |
||||
log.Error("Update", "Fail to move binary") |
||||
log.Fatal("", err.Error()) |
||||
} |
||||
os.Chmod(movePath+"/"+path.Base(tmpBinPath), os.ModePerm) |
||||
} else { |
||||
batPath := filepath.Join(tmpDirPath, "update.bat") |
||||
f, err := os.Create(batPath) |
||||
if err != nil { |
||||
log.Error("Update", "Fail to generate bat file") |
||||
log.Fatal("", err.Error()) |
||||
} |
||||
f.WriteString("@echo off\r\n") |
||||
f.WriteString(fmt.Sprintf("ping -n 1 127.0.0.1>nul\r\ncopy \"%v\" \"%v\" >nul\r\ndel \"%v\" >nul\r\n\r\n", |
||||
tmpBinPath, movePath, tmpBinPath)) |
||||
//f.WriteString(fmt.Sprintf("del \"%v\"\r\n", batPath))
|
||||
f.Close() |
||||
|
||||
attr := &os.ProcAttr{ |
||||
Dir: workDir, |
||||
Env: os.Environ(), |
||||
Files: []*os.File{os.Stdin, os.Stdout, os.Stderr}, |
||||
} |
||||
|
||||
_, err = os.StartProcess(batPath, []string{batPath}, attr) |
||||
if err != nil { |
||||
log.Error("Update", "Fail to start bat process") |
||||
log.Fatal("", err.Error()) |
||||
} |
||||
} |
||||
|
||||
log.Success("SUCC", "Update", "Command execute successfully!") |
||||
isAnythingUpdated = true |
||||
} |
||||
|
||||
// Save JSON.
|
||||
f, err := os.Create(path.Join(doc.HomeDir, doc.VER_PATH)) |
||||
if err != nil { |
||||
log.Error("Update", "Fail to create VERSION.json") |
||||
log.Fatal("", err.Error()) |
||||
} |
||||
if err := json.NewEncoder(f).Encode(&remoteVerInfo); err != nil { |
||||
log.Error("Update", "Fail to encode VERSION.json") |
||||
log.Fatal("", err.Error()) |
||||
} |
||||
|
||||
if !isAnythingUpdated { |
||||
log.Log("Nothing need to be updated") |
||||
} |
||||
log.Log("Exit old gopm") |
||||
} |
||||
|
||||
func loadLocalVerInfo() (ver version) { |
||||
verPath := path.Join(doc.HomeDir, doc.VER_PATH) |
||||
|
||||
// First time run should not exist.
|
||||
if !com.IsExist(verPath) { |
||||
return ver |
||||
} |
||||
|
||||
f, err := os.Open(verPath) |
||||
if err != nil { |
||||
log.Error("Update", "Fail to open VERSION.json") |
||||
log.Fatal("", err.Error()) |
||||
} |
||||
|
||||
if err := json.NewDecoder(f).Decode(&ver); err != nil { |
||||
log.Error("Update", "Fail to decode VERSION.json") |
||||
log.Fatal("", err.Error()) |
||||
} |
||||
return ver |
||||
} |
@ -0,0 +1,202 @@
|
||||
// Copyright 2013 gopm authors.
|
||||
//
|
||||
// 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.
|
||||
|
||||
package doc |
||||
|
||||
import ( |
||||
"archive/tar" |
||||
"bytes" |
||||
"compress/gzip" |
||||
"errors" |
||||
"io" |
||||
"net/http" |
||||
"os" |
||||
"path" |
||||
"regexp" |
||||
"strings" |
||||
|
||||
"github.com/Unknwon/com" |
||||
"github.com/codegangsta/cli" |
||||
|
||||
//"github.com/gpmgo/gopm/log"
|
||||
) |
||||
|
||||
var ( |
||||
bitbucketPattern = regexp.MustCompile(`^bitbucket\.org/(?P<owner>[a-z0-9A-Z_.\-]+)/(?P<repo>[a-z0-9A-Z_.\-]+)(?P<dir>/[a-z0-9A-Z_.\-/]*)?$`) |
||||
bitbucketEtagRe = regexp.MustCompile(`^(hg|git)-`) |
||||
) |
||||
|
||||
// getBitbucketDoc downloads tarball from bitbucket.org.
|
||||
func getBitbucketDoc(client *http.Client, match map[string]string, installRepoPath string, nod *Node, ctx *cli.Context) ([]string, error) { |
||||
// Check version control.
|
||||
if m := bitbucketEtagRe.FindStringSubmatch(nod.Value); m != nil { |
||||
match["vcs"] = m[1] |
||||
} else { |
||||
var repo struct { |
||||
Scm string |
||||
} |
||||
if err := com.HttpGetJSON(client, com.Expand("https://api.bitbucket.org/1.0/repositories/{owner}/{repo}", match), &repo); err != nil { |
||||
return nil, err |
||||
} |
||||
match["vcs"] = repo.Scm |
||||
} |
||||
|
||||
if nod.Type == BRANCH { |
||||
if len(nod.Value) == 0 { |
||||
match["commit"] = defaultTags[match["vcs"]] |
||||
} else { |
||||
match["commit"] = nod.Value |
||||
} |
||||
} |
||||
|
||||
if nod.IsGetDeps { |
||||
if nod.Type == COMMIT { |
||||
tags := make(map[string]string) |
||||
for _, nodeType := range []string{"branches", "tags"} { |
||||
var nodes map[string]struct { |
||||
Node string |
||||
} |
||||
if err := com.HttpGetJSON(client, com.Expand("https://api.bitbucket.org/1.0/repositories/{owner}/{repo}/{0}", match, nodeType), &nodes); err != nil { |
||||
return nil, err |
||||
} |
||||
for t, n := range nodes { |
||||
tags[t] = n.Node |
||||
} |
||||
} |
||||
|
||||
// Check revision tag.
|
||||
var err error |
||||
match["tag"], match["commit"], err = bestTag(tags, defaultTags[match["vcs"]]) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
nod.Value = match["commit"] |
||||
} |
||||
} else { |
||||
// Check downlaod type.
|
||||
switch nod.Type { |
||||
case TAG, COMMIT, BRANCH: |
||||
match["commit"] = nod.Value |
||||
default: |
||||
return nil, errors.New("Unknown node type: " + nod.Type) |
||||
} |
||||
} |
||||
|
||||
// We use .tar.gz here.
|
||||
// zip : https://bitbucket.org/{owner}/{repo}/get/{commit}.zip
|
||||
// tarball : https://bitbucket.org/{owner}/{repo}/get/{commit}.tar.gz
|
||||
|
||||
// Downlaod archive.
|
||||
p, err := com.HttpGetBytes(client, com.Expand("https://bitbucket.org/{owner}/{repo}/get/{commit}.tar.gz", match), nil) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
var installPath string |
||||
if nod.ImportPath == nod.DownloadURL { |
||||
suf := "." + nod.Value |
||||
if len(suf) == 1 { |
||||
suf = "" |
||||
} |
||||
projectPath := com.Expand("bitbucket.org/{owner}/{repo}", match) |
||||
installPath = installRepoPath + "/" + projectPath + suf |
||||
nod.ImportPath = projectPath |
||||
} else { |
||||
installPath = installRepoPath + "/" + nod.ImportPath |
||||
} |
||||
|
||||
// Remove old files.
|
||||
os.RemoveAll(installPath + "/") |
||||
os.MkdirAll(installPath+"/", os.ModePerm) |
||||
|
||||
gzr, err := gzip.NewReader(bytes.NewReader(p)) |
||||
if err != nil { |
||||
return 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, err |
||||
} |
||||
|
||||
fn := h.Name |
||||
|
||||
// In case that we find directory, usually we should not.
|
||||
if strings.HasSuffix(fn, "/") { |
||||
continue |
||||
} |
||||
|
||||
// Check root path.
|
||||
if len(autoPath) == 0 { |
||||
autoPath = fn[:strings.Index(fn, "/")] |
||||
} |
||||
absPath := strings.Replace(fn, autoPath, installPath, 1) |
||||
|
||||
// Create diretory before create file.
|
||||
dir := path.Dir(absPath) |
||||
if !checkDir(dir, dirs) && !(!ctx.Bool("example") && strings.Contains(absPath, "example")) { |
||||
dirs = append(dirs, dir) |
||||
os.MkdirAll(dir+"/", os.ModePerm) |
||||
} |
||||
|
||||
// Get data from archive.
|
||||
fbytes := make([]byte, h.Size) |
||||
if _, err := io.ReadFull(tr, fbytes); err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
_, err = com.SaveFile(absPath, fbytes) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
// Set modify time.
|
||||
os.Chtimes(absPath, h.AccessTime, h.ModTime) |
||||
} |
||||
|
||||
var imports []string |
||||
|
||||
// Check if need to check imports.
|
||||
if nod.IsGetDeps { |
||||
for _, d := range dirs { |
||||
importPkgs, err := CheckImports(d+"/", match["importPath"], nod) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
imports = append(imports, importPkgs...) |
||||
} |
||||
} |
||||
|
||||
return imports, err |
||||
} |
||||
|
||||
// checkDir checks if current directory has been saved.
|
||||
func checkDir(dir string, dirs []string) bool { |
||||
for _, d := range dirs { |
||||
if dir == d { |
||||
return true |
||||
} |
||||
} |
||||
return false |
||||
} |
@ -0,0 +1,147 @@
|
||||
// Copyright 2013 gopm authors.
|
||||
//
|
||||
// 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.
|
||||
|
||||
package doc |
||||
|
||||
import ( |
||||
"os" |
||||
"path" |
||||
"path/filepath" |
||||
"strings" |
||||
|
||||
"github.com/Unknwon/com" |
||||
"github.com/Unknwon/goconfig" |
||||
|
||||
"github.com/gpmgo/gopm/log" |
||||
) |
||||
|
||||
const ( |
||||
GOPM_FILE_NAME = ".gopmfile" |
||||
GOPM_CONFIG_FILE = "data/gopm.ini" |
||||
PKG_NAME_LIST_PATH = "data/pkgname.list" |
||||
VER_PATH = "data/VERSION.json" |
||||
RawHomeDir = "~/.gopm" |
||||
) |
||||
|
||||
var ( |
||||
HomeDir = "~/.gopm" |
||||
LocalNodesFile = "/data/localnodes.list" |
||||
LocalNodes *goconfig.ConfigFile |
||||
Cfg *goconfig.ConfigFile |
||||
) |
||||
|
||||
func init() { |
||||
hd, err := com.HomeDir() |
||||
if err != nil { |
||||
log.Error("", "Fail to get current user") |
||||
log.Fatal("", err.Error()) |
||||
} |
||||
|
||||
HomeDir = strings.Replace(RawHomeDir, "~", hd, -1) |
||||
|
||||
cfgPath := path.Join(HomeDir, GOPM_CONFIG_FILE) |
||||
if !com.IsExist(cfgPath) { |
||||
os.MkdirAll(path.Dir(cfgPath), os.ModePerm) |
||||
if _, err = os.Create(cfgPath); err != nil { |
||||
log.Error("", "Fail to create gopm config file") |
||||
log.Fatal("", err.Error()) |
||||
} |
||||
} |
||||
Cfg, err = goconfig.LoadConfigFile(cfgPath) |
||||
if err != nil { |
||||
log.Error("", "Fail to load gopm config file") |
||||
log.Fatal("", err.Error()) |
||||
} |
||||
|
||||
LoadLocalNodes() |
||||
LoadPkgNameList(path.Join(HomeDir, PKG_NAME_LIST_PATH)) |
||||
} |
||||
|
||||
// NewGopmfile loads gopmgile in given directory.
|
||||
func NewGopmfile(dirPath string) *goconfig.ConfigFile { |
||||
dirPath, _ = filepath.Abs(dirPath) |
||||
gf, err := goconfig.LoadConfigFile(path.Join(dirPath, GOPM_FILE_NAME)) |
||||
if err != nil { |
||||
log.Error("", "Fail to load gopmfile:") |
||||
log.Fatal("", "\t"+err.Error()) |
||||
} |
||||
return gf |
||||
} |
||||
|
||||
var PackageNameList map[string]string |
||||
|
||||
func LoadPkgNameList(filePath string) { |
||||
PackageNameList = make(map[string]string) |
||||
|
||||
// If file does not exist, simply ignore.
|
||||
if !com.IsFile(filePath) { |
||||
return |
||||
} |
||||
|
||||
data, err := com.ReadFile(filePath) |
||||
if err != nil { |
||||
log.Error("Package name list", "Fail to read file") |
||||
log.Fatal("", err.Error()) |
||||
} |
||||
|
||||
pkgs := strings.Split(string(data), "\n") |
||||
for i, line := range pkgs { |
||||
infos := strings.Split(line, "=") |
||||
if len(infos) != 2 { |
||||
// Last item might be empty line.
|
||||
if i == len(pkgs)-1 { |
||||
continue |
||||
} |
||||
log.Error("", "Fail to parse package name: "+line) |
||||
log.Fatal("", "Invalid package name information") |
||||
} |
||||
PackageNameList[strings.TrimSpace(infos[0])] = |
||||
strings.TrimSpace(infos[1]) |
||||
} |
||||
} |
||||
|
||||
func GetPkgFullPath(short string) string { |
||||
name, ok := PackageNameList[short] |
||||
if !ok { |
||||
log.Error("", "Invalid package name") |
||||
log.Error("", "It's not a invalid import path and no match in the package name list:") |
||||
log.Fatal("", "\t"+short) |
||||
} |
||||
return name |
||||
} |
||||
|
||||
func LoadLocalNodes() { |
||||
if !com.IsDir(HomeDir + "/data") { |
||||
os.MkdirAll(HomeDir+"/data", os.ModePerm) |
||||
} |
||||
|
||||
if !com.IsFile(HomeDir + LocalNodesFile) { |
||||
os.Create(HomeDir + LocalNodesFile) |
||||
} |
||||
|
||||
var err error |
||||
LocalNodes, err = goconfig.LoadConfigFile(path.Join(HomeDir + LocalNodesFile)) |
||||
if err != nil { |
||||
log.Error("load node", "Fail to load localnodes.list") |
||||
log.Fatal("", err.Error()) |
||||
} |
||||
} |
||||
|
||||
func SaveLocalNodes() { |
||||
if err := goconfig.SaveConfigFile(LocalNodes, |
||||
path.Join(HomeDir+LocalNodesFile)); err != nil { |
||||
log.Error("", "Fail to save localnodes.list:") |
||||
log.Error("", "\t"+err.Error()) |
||||
} |
||||
} |
@ -0,0 +1,25 @@
|
||||
// Copyright 2013 gopm authors.
|
||||
//
|
||||
// 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.
|
||||
|
||||
package doc |
||||
|
||||
import ( |
||||
"errors" |
||||
) |
||||
|
||||
var ( |
||||
errNotModified = errors.New("Package not modified") |
||||
errNoMatch = errors.New("no match") |
||||
errUpdateTimeout = errors.New("update timeout") |
||||
) |
@ -0,0 +1,191 @@
|
||||
// Copyright 2013 gopm authors.
|
||||
//
|
||||
// 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.
|
||||
|
||||
package doc |
||||
|
||||
import ( |
||||
"archive/zip" |
||||
"bytes" |
||||
"errors" |
||||
"io" |
||||
"net/http" |
||||
"os" |
||||
"path" |
||||
"regexp" |
||||
"strings" |
||||
|
||||
"github.com/Unknwon/com" |
||||
"github.com/codegangsta/cli" |
||||
|
||||
"github.com/gpmgo/gopm/log" |
||||
) |
||||
|
||||
var ( |
||||
githubPattern = regexp.MustCompile(`^github\.com/(?P<owner>[a-z0-9A-Z_.\-]+)/(?P<repo>[a-z0-9A-Z_.\-]+)(?P<dir>/[a-z0-9A-Z_.\-/]*)?$`) |
||||
) |
||||
|
||||
func GetGithubCredentials() string { |
||||
return "client_id=" + Cfg.MustValue("github", "client_id") + |
||||
"&client_secret=" + Cfg.MustValue("github", "client_secret") |
||||
} |
||||
|
||||
// getGithubDoc downloads tarball from github.com.
|
||||
func getGithubDoc(client *http.Client, match map[string]string, installRepoPath string, nod *Node, ctx *cli.Context) ([]string, error) { |
||||
match["cred"] = GetGithubCredentials() |
||||
|
||||
// Check downlaod type.
|
||||
switch nod.Type { |
||||
case BRANCH: |
||||
if len(nod.Value) == 0 { |
||||
match["sha"] = MASTER |
||||
|
||||
// Only get and check revision with the latest version.
|
||||
var refs []*struct { |
||||
Ref string |
||||
Url string |
||||
Object struct { |
||||
Sha string |
||||
Type string |
||||
Url string |
||||
} |
||||
} |
||||
|
||||
err := com.HttpGetJSON(client, com.Expand("https://api.github.com/repos/{owner}/{repo}/git/refs?{cred}", match), &refs) |
||||
if err != nil { |
||||
if strings.Contains(err.Error(), "403") { |
||||
break |
||||
} |
||||
log.Warn("GET", "Fail to get revision") |
||||
log.Warn("", err.Error()) |
||||
break |
||||
} |
||||
|
||||
var etag string |
||||
COMMIT_LOOP: |
||||
for _, ref := range refs { |
||||
switch { |
||||
case strings.HasPrefix(ref.Ref, "refs/heads/master"): |
||||
etag = ref.Object.Sha |
||||
break COMMIT_LOOP |
||||
} |
||||
} |
||||
if etag == nod.Revision { |
||||
log.Log("GET Package hasn't changed: %s", nod.ImportPath) |
||||
return nil, nil |
||||
} |
||||
nod.Revision = etag |
||||
|
||||
} else { |
||||
match["sha"] = nod.Value |
||||
} |
||||
case TAG, COMMIT: |
||||
match["sha"] = nod.Value |
||||
default: |
||||
return nil, errors.New("Unknown node type: " + nod.Type) |
||||
} |
||||
|
||||
// We use .zip here.
|
||||
// zip: https://github.com/{owner}/{repo}/archive/{sha}.zip
|
||||
// tarball: https://github.com/{owner}/{repo}/tarball/{sha}
|
||||
|
||||
// Downlaod archive.
|
||||
p, err := com.HttpGetBytes(client, com.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()) |
||||
} |
||||
|
||||
shaName := com.Expand("{repo}-{sha}", match) |
||||
if nod.Type == "tag" { |
||||
shaName = strings.Replace(shaName, "-v", "-", 1) |
||||
} |
||||
|
||||
var installPath string |
||||
if nod.ImportPath == nod.DownloadURL { |
||||
suf := "." + nod.Value |
||||
if len(suf) == 1 { |
||||
suf = "" |
||||
} |
||||
projectPath := com.Expand("github.com/{owner}/{repo}", match) |
||||
installPath = installRepoPath + "/" + projectPath + suf |
||||
nod.ImportPath = projectPath |
||||
} else { |
||||
installPath = installRepoPath + "/" + nod.ImportPath |
||||
} |
||||
|
||||
// Remove old files.
|
||||
os.RemoveAll(installPath + "/") |
||||
os.MkdirAll(installPath+"/", os.ModePerm) |
||||
|
||||
r, err := zip.NewReader(bytes.NewReader(p), int64(len(p))) |
||||
if err != nil { |
||||
return nil, errors.New(nod.ImportPath + " -> new zip: " + err.Error()) |
||||
} |
||||
|
||||
dirs := make([]string, 0, 5) |
||||
// Need to add root path because we cannot get from tarball.
|
||||
dirs = append(dirs, installPath+"/") |
||||
for _, f := range r.File { |
||||
absPath := strings.Replace(f.Name, shaName, installPath, 1) |
||||
// Create diretory before create file.
|
||||
os.MkdirAll(path.Dir(absPath)+"/", os.ModePerm) |
||||
|
||||
compareDir: |
||||
switch { |
||||
case strings.HasSuffix(absPath, "/"): // Directory.
|
||||
// Check if current directory is example.
|
||||
if !(!ctx.Bool("example") && strings.Contains(absPath, "example")) { |
||||
for _, d := range dirs { |
||||
if d == absPath { |
||||
break compareDir |
||||
} |
||||
} |
||||
dirs = append(dirs, absPath) |
||||
} |
||||
default: |
||||
// Get file from archive.
|
||||
r, err := f.Open() |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
fbytes := make([]byte, f.FileInfo().Size()) |
||||
_, err = io.ReadFull(r, fbytes) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
_, err = com.SaveFile(absPath, fbytes) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
// Set modify time.
|
||||
os.Chtimes(absPath, f.ModTime(), f.ModTime()) |
||||
} |
||||
} |
||||
|
||||
var imports []string |
||||
|
||||
// Check if need to check imports.
|
||||
if nod.IsGetDeps { |
||||
for _, d := range dirs { |
||||
importPkgs, err := CheckImports(d, match["importPath"], nod) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
imports = append(imports, importPkgs...) |
||||
} |
||||
} |
||||
return imports, err |
||||
} |
@ -0,0 +1,286 @@
|
||||
// Copyright 2013 gopm authors.
|
||||
//
|
||||
// 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.
|
||||
|
||||
package doc |
||||
|
||||
import ( |
||||
"archive/zip" |
||||
"bytes" |
||||
"errors" |
||||
"io" |
||||
"net/http" |
||||
"os" |
||||
"path" |
||||
"regexp" |
||||
"strings" |
||||
|
||||
"github.com/Unknwon/com" |
||||
"github.com/codegangsta/cli" |
||||
|
||||
"github.com/gpmgo/gopm/log" |
||||
) |
||||
|
||||
var ( |
||||
googleRepoRe = regexp.MustCompile(`id="checkoutcmd">(hg|git|svn)`) |
||||
googleRevisionRe = regexp.MustCompile(`<h2>(?:[^ ]+ - )?Revision *([^:]+):`) |
||||
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_.\-/]+)?$`) |
||||
) |
||||
|
||||
// getGoogleDoc downloads raw files from code.google.com.
|
||||
func getGoogleDoc(client *http.Client, match map[string]string, installRepoPath string, nod *Node, ctx *cli.Context) ([]string, error) { |
||||
setupGoogleMatch(match) |
||||
// Check version control.
|
||||
if err := getGoogleVCS(client, match); err != nil { |
||||
return nil, errors.New("fail to get vcs " + nod.ImportPath + " : " + err.Error()) |
||||
} |
||||
|
||||
switch nod.Type { |
||||
case BRANCH: |
||||
if len(nod.Value) == 0 { |
||||
match["tag"] = defaultTags[match["vcs"]] |
||||
|
||||
// Only get and check revision with the latest version.
|
||||
p, err := com.HttpGetBytes(client, |
||||
com.Expand("http://{subrepo}{dot}{repo}.googlecode.com/{vcs}{dir}/?r={tag}", match), nil) |
||||
if err != nil { |
||||
log.Error("GET", "Fail to get revision") |
||||
log.Error("", err.Error()) |
||||
break |
||||
} |
||||
|
||||
if m := googleRevisionRe.FindSubmatch(p); m == nil { |
||||
log.Error("GET", "Fail to get revision") |
||||
log.Error("", err.Error()) |
||||
} else { |
||||
etag := string(m[1]) |
||||
if etag == nod.Revision { |
||||
log.Log("GET Package hasn't changed: %s", nod.ImportPath) |
||||
return nil, nil |
||||
} |
||||
nod.Revision = etag |
||||
} |
||||
|
||||
} else { |
||||
match["tag"] = nod.Value |
||||
} |
||||
case TAG, COMMIT: |
||||
match["tag"] = nod.Value |
||||
default: |
||||
return nil, errors.New("Unknown node type: " + nod.Type) |
||||
} |
||||
|
||||
var installPath string |
||||
projectPath := GetProjectPath(nod.ImportPath) |
||||
if nod.ImportPath == nod.DownloadURL { |
||||
suf := "." + nod.Value |
||||
if len(suf) == 1 { |
||||
suf = "" |
||||
} |
||||
installPath = installRepoPath + "/" + projectPath + suf |
||||
} else { |
||||
installPath = installRepoPath + "/" + projectPath |
||||
} |
||||
|
||||
// Remove old files.
|
||||
os.RemoveAll(installPath + "/") |
||||
os.MkdirAll(installPath+"/", os.ModePerm) |
||||
|
||||
if match["vcs"] == "svn" { |
||||
com.ColorLog("[WARN] SVN detected, may take very long time.\n") |
||||
|
||||
rootPath := com.Expand("http://{subrepo}{dot}{repo}.googlecode.com/{vcs}", match) |
||||
d, f := path.Split(rootPath) |
||||
err := downloadFiles(client, match, d, installPath+"/", match["tag"], |
||||
[]string{f + "/"}) |
||||
if err != nil { |
||||
return nil, errors.New("Fail to download " + nod.ImportPath + " : " + err.Error()) |
||||
} |
||||
} |
||||
|
||||
p, err := com.HttpGetBytes(client, com.Expand("http://{subrepo}{dot}{repo}.googlecode.com/archive/{tag}.zip", match), nil) |
||||
if err != nil { |
||||
return nil, errors.New("Fail to download " + nod.ImportPath + " : " + err.Error()) |
||||
} |
||||
|
||||
r, err := zip.NewReader(bytes.NewReader(p), int64(len(p))) |
||||
if err != nil { |
||||
return nil, errors.New(nod.ImportPath + " -> new zip: " + err.Error()) |
||||
} |
||||
|
||||
nameLen := strings.Index(r.File[0].Name, "/") |
||||
dirPrefix := match["dir"] |
||||
if len(dirPrefix) != 0 { |
||||
dirPrefix = dirPrefix[1:] + "/" |
||||
} |
||||
|
||||
dirs := make([]string, 0, 5) |
||||
for _, f := range r.File { |
||||
absPath := strings.Replace(f.Name, f.Name[:nameLen], installPath, 1) |
||||
|
||||
// Create diretory before create file.
|
||||
dir := path.Dir(absPath) |
||||
if !checkDir(dir, dirs) && !(!ctx.Bool("example") && strings.Contains(absPath, "example")) { |
||||
dirs = append(dirs, dir+"/") |
||||
os.MkdirAll(dir+"/", os.ModePerm) |
||||
} |
||||
|
||||
// Get file from archive.
|
||||
r, err := f.Open() |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
fbytes := make([]byte, f.FileInfo().Size()) |
||||
_, err = io.ReadFull(r, fbytes) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
_, err = com.SaveFile(absPath, fbytes) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
} |
||||
|
||||
var imports []string |
||||
|
||||
// Check if need to check imports.
|
||||
if nod.IsGetDeps { |
||||
for _, d := range dirs { |
||||
importPkgs, err := CheckImports(d, match["importPath"], nod) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
imports = append(imports, importPkgs...) |
||||
} |
||||
} |
||||
|
||||
return imports, err |
||||
} |
||||
|
||||
type rawFile struct { |
||||
name string |
||||
rawURL string |
||||
data []byte |
||||
} |
||||
|
||||
func (rf *rawFile) Name() string { |
||||
return rf.name |
||||
} |
||||
|
||||
func (rf *rawFile) RawUrl() string { |
||||
return rf.rawURL |
||||
} |
||||
|
||||
func (rf *rawFile) Data() []byte { |
||||
return rf.data |
||||
} |
||||
|
||||
func (rf *rawFile) SetData(p []byte) { |
||||
rf.data = p |
||||
} |
||||
|
||||
func downloadFiles(client *http.Client, match map[string]string, rootPath, installPath, commit string, dirs []string) error { |
||||
suf := "?r=" + commit |
||||
if len(commit) == 0 { |
||||
suf = "" |
||||
} |
||||
|
||||
for _, d := range dirs { |
||||
p, err := com.HttpGetBytes(client, rootPath+d+suf, nil) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
|
||||
// Create destination directory.
|
||||
os.MkdirAll(installPath+d, os.ModePerm) |
||||
|
||||
// Get source files in current path.
|
||||
files := make([]com.RawFile, 0, 5) |
||||
for _, m := range googleFileRe.FindAllSubmatch(p, -1) { |
||||
fname := strings.Split(string(m[1]), "?")[0] |
||||
files = append(files, &rawFile{ |
||||
name: fname, |
||||
rawURL: rootPath + d + fname + suf, |
||||
}) |
||||
} |
||||
|
||||
// Fetch files from VCS.
|
||||
if err := com.FetchFilesCurl(files); 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 |
||||
} |
||||
} |
||||
files = nil |
||||
|
||||
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 |
||||
} |
||||
|
||||
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 := com.HttpGetBytes(client, com.Expand("http://code.google.com/p/{repo}/source/checkout", match), nil) |
||||
if err != nil { |
||||
return errors.New("doc.getGoogleVCS(" + match["importPath"] + ") -> " + err.Error()) |
||||
} |
||||
m := googleRepoRe.FindSubmatch(p) |
||||
if m == nil { |
||||
return com.NotFoundError{"Could not VCS on Google Code project page."} |
||||
} |
||||
match["vcs"] = string(m[1]) |
||||
return nil |
||||
} |
@ -0,0 +1,52 @@
|
||||
// Copyright 2013 gopm authors.
|
||||
//
|
||||
// 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.
|
||||
|
||||
package doc |
||||
|
||||
import ( |
||||
"flag" |
||||
"net" |
||||
"net/http" |
||||
"time" |
||||
|
||||
"github.com/Unknwon/com" |
||||
) |
||||
|
||||
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.") |
||||
) |
||||
|
||||
func timeoutDial(network, addr string) (net.Conn, error) { |
||||
return net.DialTimeout(network, addr, *dialTimeout) |
||||
} |
||||
|
||||
type transport struct { |
||||
t http.Transport |
||||
} |
||||
|
||||
func (t *transport) RoundTrip(req *http.Request) (*http.Response, error) { |
||||
timer := time.AfterFunc(*requestTimeout, func() { |
||||
t.t.CancelRequest(req) |
||||
com.ColorLog("[WARN] Canceled request for %s, please interrupt the program.\n", req.URL) |
||||
}) |
||||
defer timer.Stop() |
||||
resp, err := t.t.RoundTrip(req) |
||||
return resp, err |
||||
} |
||||
|
||||
var ( |
||||
httpTransport = &transport{t: http.Transport{Dial: timeoutDial, ResponseHeaderTimeout: *requestTimeout / 2}} |
||||
HttpClient = &http.Client{Transport: httpTransport} |
||||
) |
@ -0,0 +1,134 @@
|
||||
// Copyright 2013 gopm authors.
|
||||
//
|
||||
// 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.
|
||||
|
||||
package doc |
||||
|
||||
import ( |
||||
"archive/tar" |
||||
"bytes" |
||||
"compress/gzip" |
||||
"io" |
||||
"net/http" |
||||
"os" |
||||
"regexp" |
||||
"strings" |
||||
|
||||
"github.com/Unknwon/com" |
||||
"github.com/codegangsta/cli" |
||||
) |
||||
|
||||
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_.\-/]+)*$`) |
||||
|
||||
// getLaunchpadDoc downloads tarball from launchpad.net.
|
||||
func getLaunchpadDoc(client *http.Client, match map[string]string, installRepoPath string, nod *Node, ctx *cli.Context) ([]string, error) { |
||||
|
||||
if match["project"] != "" && match["series"] != "" { |
||||
rc, err := com.HttpGet(client, com.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: |
||||
// The structure of the import path is is launchpad.net/{project}/{dir}.
|
||||
match["repo"] = match["project"] |
||||
match["dir"] = com.Expand("{series}{dir}", match) |
||||
default: |
||||
return nil, err |
||||
} |
||||
} |
||||
|
||||
var downloadPath string |
||||
// Check if download with specific revision.
|
||||
if len(nod.Value) == 0 { |
||||
downloadPath = com.Expand("https://bazaar.launchpad.net/+branch/{repo}/tarball", match) |
||||
} else { |
||||
downloadPath = com.Expand("https://bazaar.launchpad.net/+branch/{repo}/tarball/"+nod.Value, match) |
||||
} |
||||
|
||||
// Scrape the repo browser to find the project revision and individual Go files.
|
||||
p, err := com.HttpGetBytes(client, downloadPath, nil) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
installPath := installRepoPath + "/" + nod.ImportPath |
||||
|
||||
// Remove old files.
|
||||
os.RemoveAll(installPath + "/") |
||||
os.MkdirAll(installPath+"/", os.ModePerm) |
||||
|
||||
gzr, err := gzip.NewReader(bytes.NewReader(p)) |
||||
if err != nil { |
||||
return 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, err |
||||
} |
||||
|
||||
fn := h.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) |
||||
|
||||
switch { |
||||
case h.FileInfo().IsDir(): // Directory.
|
||||
// Create diretory before create file.
|
||||
os.MkdirAll(absPath+"/", os.ModePerm) |
||||
// Check if current directory is example.
|
||||
if !(!ctx.Bool("example") && strings.Contains(absPath, "example")) { |
||||
dirs = append(dirs, absPath) |
||||
} |
||||
case !strings.HasPrefix(fn, "."): |
||||
// Get data from archive.
|
||||
fbytes := make([]byte, h.Size) |
||||
if _, err := io.ReadFull(tr, fbytes); err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
_, err = com.SaveFile(absPath, fbytes) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
} |
||||
} |
||||
|
||||
var imports []string |
||||
|
||||
// Check if need to check imports.
|
||||
if nod.IsGetDeps { |
||||
for _, d := range dirs { |
||||
importPkgs, err := CheckImports(d+"/", match["importPath"], nod) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
imports = append(imports, importPkgs...) |
||||
} |
||||
} |
||||
|
||||
return imports, err |
||||
} |
@ -0,0 +1,128 @@
|
||||
// Copyright 2013 gopm authors.
|
||||
//
|
||||
// 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.
|
||||
|
||||
package doc |
||||
|
||||
import ( |
||||
"archive/zip" |
||||
"bytes" |
||||
"errors" |
||||
"io" |
||||
"net/http" |
||||
"os" |
||||
"regexp" |
||||
"strings" |
||||
|
||||
"github.com/Unknwon/com" |
||||
"github.com/codegangsta/cli" |
||||
) |
||||
|
||||
var ( |
||||
oscTagRe = regexp.MustCompile(`/repository/archive\?ref=(.*)">`) |
||||
oscPattern = regexp.MustCompile(`^git\.oschina\.net/(?P<owner>[a-z0-9A-Z_.\-]+)/(?P<repo>[a-z0-9A-Z_.\-]+)(?P<dir>/[a-z0-9A-Z_.\-/]*)?$`) |
||||
) |
||||
|
||||
// getGithubDoc downloads tarball from git.oschina.com.
|
||||
func getOSCDoc(client *http.Client, match map[string]string, installRepoPath string, nod *Node, ctx *cli.Context) ([]string, error) { |
||||
// Check downlaod type.
|
||||
switch nod.Type { |
||||
case BRANCH: |
||||
if len(nod.Value) == 0 { |
||||
match["sha"] = MASTER |
||||
} else { |
||||
match["sha"] = nod.Value |
||||
} |
||||
case TAG, COMMIT: |
||||
match["sha"] = nod.Value |
||||
default: |
||||
return nil, errors.New("Unknown node type: " + nod.Type) |
||||
} |
||||
|
||||
// zip: http://{projectRoot}/repository/archive?ref={sha}
|
||||
|
||||
// Downlaod archive.
|
||||
p, err := com.HttpGetBytes(client, com.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()) |
||||
} |
||||
|
||||
var installPath string |
||||
if nod.ImportPath == nod.DownloadURL { |
||||
suf := "." + nod.Value |
||||
if len(suf) == 1 { |
||||
suf = "" |
||||
} |
||||
projectPath := com.Expand("git.oschina.net/{owner}/{repo}", match) |
||||
installPath = installRepoPath + "/" + projectPath + suf |
||||
nod.ImportPath = projectPath |
||||
} else { |
||||
installPath = installRepoPath + "/" + nod.ImportPath |
||||
} |
||||
|
||||
// Remove old files.
|
||||
os.RemoveAll(installPath + "/") |
||||
os.MkdirAll(installPath+"/", os.ModePerm) |
||||
|
||||
r, err := zip.NewReader(bytes.NewReader(p), int64(len(p))) |
||||
if err != nil { |
||||
return nil, errors.New("Fail to unzip OSChina repo -> " + err.Error()) |
||||
} |
||||
|
||||
nameLen := len(match["repo"]) |
||||
dirs := make([]string, 0, 5) |
||||
// Need to add root path because we cannot get from tarball.
|
||||
dirs = append(dirs, installPath+"/") |
||||
for _, f := range r.File { |
||||
fileName := f.Name[nameLen+1:] |
||||
absPath := installPath + "/" + fileName |
||||
|
||||
if strings.HasSuffix(absPath, "/") { |
||||
dirs = append(dirs, absPath) |
||||
os.MkdirAll(absPath, os.ModePerm) |
||||
continue |
||||
} |
||||
|
||||
// Get file from archive.
|
||||
r, err := f.Open() |
||||
if err != nil { |
||||
return nil, errors.New("Fail to open OSChina repo -> " + err.Error()) |
||||
} |
||||
|
||||
fbytes := make([]byte, f.FileInfo().Size()) |
||||
_, err = io.ReadFull(r, fbytes) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
_, err = com.SaveFile(absPath, fbytes) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
} |
||||
|
||||
var imports []string |
||||
|
||||
// Check if need to check imports.
|
||||
if nod.IsGetDeps { |
||||
for _, d := range dirs { |
||||
importPkgs, err := CheckImports(d, match["importPath"], nod) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
imports = append(imports, importPkgs...) |
||||
} |
||||
} |
||||
|
||||
return imports, err |
||||
} |
@ -0,0 +1,125 @@
|
||||
// Copyright 2013 gopm authors.
|
||||
//
|
||||
// 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.
|
||||
|
||||
package doc |
||||
|
||||
import ( |
||||
"fmt" |
||||
"go/token" |
||||
"net/http" |
||||
"os" |
||||
"regexp" |
||||
"time" |
||||
|
||||
"github.com/codegangsta/cli" |
||||
) |
||||
|
||||
const ( |
||||
TRUNK = "trunk" |
||||
MASTER = "master" |
||||
DEFAULT = "default" |
||||
TAG = "tag" |
||||
BRANCH = "branch" |
||||
COMMIT = "commit" |
||||
LOCAL = "local" |
||||
) |
||||
|
||||
type Pkg struct { |
||||
ImportPath string |
||||
RootPath string |
||||
Type string |
||||
Value string // Branch, tag, commit or local.
|
||||
} |
||||
|
||||
// If the package is fixed and no need to updated.
|
||||
// For commit, tag and local, it's fixed. For branch
|
||||
func (pkg *Pkg) IsFixed() bool { |
||||
if pkg.Type == BRANCH || len(pkg.Value) == 0 { |
||||
return false |
||||
} |
||||
return true |
||||
} |
||||
|
||||
func (pkg *Pkg) VerString() string { |
||||
if pkg.Value == "" { |
||||
return pkg.Type |
||||
} |
||||
return fmt.Sprintf("%v:%v", pkg.Type, pkg.Value) |
||||
} |
||||
|
||||
func NewPkg(importPath, tp, value string) *Pkg { |
||||
return &Pkg{importPath, "", tp, value} |
||||
} |
||||
|
||||
func NewDefaultPkg(importPath string) *Pkg { |
||||
return NewPkg(importPath, BRANCH, "") |
||||
} |
||||
|
||||
type Node struct { |
||||
Pkg |
||||
DownloadURL string |
||||
Synopsis string |
||||
IsGetDeps bool |
||||
IsGetDepsOnly bool |
||||
Revision string |
||||
} |
||||
|
||||
func NewNode(importPath, downloadUrl, tp, value string, isGetDeps bool) *Node { |
||||
return &Node{ |
||||
Pkg: Pkg{ |
||||
ImportPath: importPath, |
||||
Type: tp, |
||||
Value: value, |
||||
}, |
||||
DownloadURL: downloadUrl, |
||||
IsGetDeps: isGetDeps, |
||||
} |
||||
} |
||||
|
||||
// source is source code file.
|
||||
type source struct { |
||||
rawURL string |
||||
name string |
||||
data []byte |
||||
} |
||||
|
||||
func (s *source) Name() string { return s.name } |
||||
func (s *source) Size() int64 { return int64(len(s.data)) } |
||||
func (s *source) Mode() os.FileMode { return 0 } |
||||
func (s *source) ModTime() time.Time { return time.Time{} } |
||||
func (s *source) IsDir() bool { return false } |
||||
func (s *source) Sys() interface{} { return nil } |
||||
|
||||
// walker holds the state used when building the documentation.
|
||||
type walker struct { |
||||
ImportPath string |
||||
srcs map[string]*source // Source files.
|
||||
fset *token.FileSet |
||||
} |
||||
|
||||
// service represents a source code control service.
|
||||
type service struct { |
||||
pattern *regexp.Regexp |
||||
prefix string |
||||
get func(*http.Client, map[string]string, string, *Node, *cli.Context) ([]string, error) |
||||
} |
||||
|
||||
// services is the list of source code control services handled by gopkgdoc.
|
||||
var services = []*service{ |
||||
{githubPattern, "github.com/", getGithubDoc}, |
||||
{googlePattern, "code.google.com/", getGoogleDoc}, |
||||
{bitbucketPattern, "bitbucket.org/", getBitbucketDoc}, |
||||
{launchpadPattern, "launchpad.net/", getLaunchpadDoc}, |
||||
{oscPattern, "git.oschina.net/", getOSCDoc}, |
||||
} |
@ -0,0 +1,759 @@
|
||||
// Copyright 2013-2014 gopm authors.
|
||||
//
|
||||
// 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.
|
||||
|
||||
package doc |
||||
|
||||
import ( |
||||
"bytes" |
||||
"go/build" |
||||
"io" |
||||
"io/ioutil" |
||||
"os" |
||||
"path" |
||||
"path/filepath" |
||||
"regexp" |
||||
"strings" |
||||
"time" |
||||
|
||||
"github.com/Unknwon/com" |
||||
|
||||
"github.com/gpmgo/gopm/log" |
||||
) |
||||
|
||||
const VENDOR = ".vendor" |
||||
|
||||
// GetDirsInfo returns os.FileInfo of all sub-directories in root path.
|
||||
func GetDirsInfo(rootPath string) ([]os.FileInfo, error) { |
||||
if !com.IsDir(rootPath) { |
||||
log.Warn("Directory %s does not exist", rootPath) |
||||
return []os.FileInfo{}, nil |
||||
} |
||||
|
||||
rootDir, err := os.Open(rootPath) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
defer rootDir.Close() |
||||
|
||||
dirs, err := rootDir.Readdir(0) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
return dirs, nil |
||||
} |
||||
|
||||
// A Source describles a Source code file.
|
||||
type Source struct { |
||||
SrcName string |
||||
SrcData []byte |
||||
} |
||||
|
||||
func (s *Source) Name() string { return s.SrcName } |
||||
func (s *Source) Size() int64 { return int64(len(s.SrcData)) } |
||||
func (s *Source) Mode() os.FileMode { return 0 } |
||||
func (s *Source) ModTime() time.Time { return time.Time{} } |
||||
func (s *Source) IsDir() bool { return false } |
||||
func (s *Source) Sys() interface{} { return nil } |
||||
func (s *Source) Data() []byte { return s.SrcData } |
||||
|
||||
type Context struct { |
||||
build.Context |
||||
importPath string |
||||
srcFiles map[string]*Source |
||||
} |
||||
|
||||
func (ctx *Context) readDir(dir string) ([]os.FileInfo, error) { |
||||
fis := make([]os.FileInfo, 0, len(ctx.srcFiles)) |
||||
for _, src := range ctx.srcFiles { |
||||
fis = append(fis, src) |
||||
} |
||||
return fis, nil |
||||
} |
||||
|
||||
func (ctx *Context) openFile(path string) (r io.ReadCloser, err error) { |
||||
if src, ok := ctx.srcFiles[filepath.Base(path)]; ok { |
||||
return ioutil.NopCloser(bytes.NewReader(src.Data())), nil |
||||
} |
||||
return nil, os.ErrNotExist |
||||
} |
||||
|
||||
// GetImports returns package denpendencies.
|
||||
func GetImports(absPath, importPath string, example, test bool) []string { |
||||
fis, err := GetDirsInfo(absPath) |
||||
if err != nil { |
||||
log.Error("", "Fail to get directory's information") |
||||
log.Fatal("", err.Error()) |
||||
} |
||||
absPath += "/" |
||||
|
||||
ctx := new(Context) |
||||
ctx.importPath = importPath |
||||
ctx.srcFiles = make(map[string]*Source) |
||||
ctx.Context = build.Default |
||||
ctx.JoinPath = path.Join |
||||
ctx.IsAbsPath = path.IsAbs |
||||
ctx.ReadDir = ctx.readDir |
||||
ctx.OpenFile = ctx.openFile |
||||
|
||||
// TODO: Load too much, need to make sure which is imported which are not.
|
||||
dirs := make([]string, 0, 10) |
||||
for _, fi := range fis { |
||||
if strings.Contains(fi.Name(), VENDOR) { |
||||
continue |
||||
} |
||||
|
||||
if fi.IsDir() { |
||||
dirs = append(dirs, absPath+fi.Name()) |
||||
continue |
||||
} else if !test && strings.HasSuffix(fi.Name(), "_test.go") { |
||||
continue |
||||
} else if !strings.HasSuffix(fi.Name(), ".go") || strings.HasPrefix(fi.Name(), ".") || |
||||
strings.HasPrefix(fi.Name(), "_") { |
||||
continue |
||||
} |
||||
src := &Source{SrcName: fi.Name()} |
||||
src.SrcData, err = ioutil.ReadFile(absPath + fi.Name()) |
||||
if err != nil { |
||||
log.Error("", "Fail to read file") |
||||
log.Fatal("", err.Error()) |
||||
} |
||||
ctx.srcFiles[fi.Name()] = src |
||||
} |
||||
|
||||
pkg, err := ctx.ImportDir(absPath, build.AllowBinary) |
||||
if err != nil { |
||||
if _, ok := err.(*build.NoGoError); !ok { |
||||
log.Error("", "Fail to get imports") |
||||
log.Fatal("", err.Error()) |
||||
} |
||||
} |
||||
|
||||
imports := make([]string, 0, len(pkg.Imports)) |
||||
for _, p := range pkg.Imports { |
||||
if !IsGoRepoPath(p) && !strings.HasPrefix(p, importPath) { |
||||
imports = append(imports, p) |
||||
} |
||||
} |
||||
|
||||
if len(dirs) > 0 { |
||||
imports = append(imports, GetAllImports(dirs, importPath, example, test)...) |
||||
} |
||||
return imports |
||||
} |
||||
|
||||
// isVcsPath returns true if the directory was created by VCS.
|
||||
func isVcsPath(dirPath string) bool { |
||||
return strings.Contains(dirPath, "/.git") || |
||||
strings.Contains(dirPath, "/.hg") || |
||||
strings.Contains(dirPath, "/.svn") |
||||
} |
||||
|
||||
// GetAllImports returns all imports in given directory and all sub-directories.
|
||||
func GetAllImports(dirs []string, importPath string, example, test bool) (imports []string) { |
||||
for _, d := range dirs { |
||||
if !isVcsPath(d) && |
||||
!(!example && strings.Contains(d, "example")) { |
||||
imports = append(imports, GetImports(d, importPath, example, test)...) |
||||
} |
||||
} |
||||
return imports |
||||
} |
||||
|
||||
// GetGOPATH returns best matched GOPATH.
|
||||
func GetBestMatchGOPATH(appPath string) string { |
||||
paths := com.GetGOPATHs() |
||||
for _, p := range paths { |
||||
if strings.HasPrefix(p, appPath) { |
||||
return strings.Replace(p, "\\", "/", -1) |
||||
} |
||||
} |
||||
return paths[0] |
||||
} |
||||
|
||||
// CheckIsExistWithVCS returns false if directory only has VCS folder,
|
||||
// or doesn't exist.
|
||||
func CheckIsExistWithVCS(path string) bool { |
||||
// Check if directory exist.
|
||||
if !com.IsExist(path) { |
||||
return false |
||||
} |
||||
|
||||
// Check if only has VCS folder.
|
||||
dirs, err := GetDirsInfo(path) |
||||
if err != nil { |
||||
log.Error("", "Fail to get directory's information") |
||||
log.Fatal("", err.Error()) |
||||
} |
||||
|
||||
if len(dirs) > 1 { |
||||
return true |
||||
} else if len(dirs) == 0 { |
||||
return false |
||||
} |
||||
|
||||
switch dirs[0].Name() { |
||||
case ".git", ".hg", ".svn": |
||||
return false |
||||
} |
||||
|
||||
return true |
||||
} |
||||
|
||||
// CheckIsExistInGOPATH checks if given package import path exists in any path in GOPATH/src,
|
||||
// and returns corresponding GOPATH.
|
||||
func CheckIsExistInGOPATH(importPath string) (string, bool) { |
||||
paths := com.GetGOPATHs() |
||||
for _, p := range paths { |
||||
if CheckIsExistWithVCS(p + "/src/" + importPath + "/") { |
||||
return p, true |
||||
} |
||||
} |
||||
return "", false |
||||
} |
||||
|
||||
// GetProjectPath returns project path of import path.
|
||||
func GetProjectPath(importPath string) (projectPath string) { |
||||
projectPath = importPath |
||||
|
||||
// Check project hosting.
|
||||
switch { |
||||
case strings.HasPrefix(importPath, "github.com") || |
||||
strings.HasPrefix(importPath, "git.oschina.net"): |
||||
projectPath = joinPath(importPath, 3) |
||||
case strings.HasPrefix(importPath, "code.google.com"): |
||||
projectPath = joinPath(importPath, 3) |
||||
case strings.HasPrefix(importPath, "bitbucket.org"): |
||||
projectPath = joinPath(importPath, 3) |
||||
case strings.HasPrefix(importPath, "launchpad.net"): |
||||
projectPath = joinPath(importPath, 2) |
||||
} |
||||
|
||||
return projectPath |
||||
} |
||||
|
||||
func joinPath(importPath string, num int) string { |
||||
subdirs := strings.Split(importPath, "/") |
||||
if len(subdirs) > num { |
||||
return strings.Join(subdirs[:num], "/") |
||||
} |
||||
return importPath |
||||
} |
||||
|
||||
var validTLD = map[string]bool{ |
||||
// curl http://data.iana.org/TLD/tlds-alpha-by-domain.txt | sed -e '/#/ d' -e 's/.*/"&": true,/' | tr [:upper:] [:lower:]
|
||||
".ac": true, |
||||
".ad": true, |
||||
".ae": true, |
||||
".aero": true, |
||||
".af": true, |
||||
".ag": true, |
||||
".ai": true, |
||||
".al": true, |
||||
".am": true, |
||||
".an": true, |
||||
".ao": true, |
||||
".aq": true, |
||||
".ar": true, |
||||
".arpa": true, |
||||
".as": true, |
||||
".asia": true, |
||||
".at": true, |
||||
".au": true, |
||||
".aw": true, |
||||
".ax": true, |
||||
".az": true, |
||||
".ba": true, |
||||
".bb": true, |
||||
".bd": true, |
||||
".be": true, |
||||
".bf": true, |
||||
".bg": true, |
||||
".bh": true, |
||||
".bi": true, |
||||
".biz": true, |
||||
".bj": true, |
||||
".bm": true, |
||||
".bn": true, |
||||
".bo": true, |
||||
".br": true, |
||||
".bs": true, |
||||
".bt": true, |
||||
".bv": true, |
||||
".bw": true, |
||||
".by": true, |
||||
".bz": true, |
||||
".ca": true, |
||||
".cat": true, |
||||
".cc": true, |
||||
".cd": true, |
||||
".cf": true, |
||||
".cg": true, |
||||
".ch": true, |
||||
".ci": true, |
||||
".ck": true, |
||||
".cl": true, |
||||
".cm": true, |
||||
".cn": true, |
||||
".co": true, |
||||
".com": true, |
||||
".coop": true, |
||||
".cr": true, |
||||
".cu": true, |
||||
".cv": true, |
||||
".cw": true, |
||||
".cx": true, |
||||
".cy": true, |
||||
".cz": true, |
||||
".de": true, |
||||
".dj": true, |
||||
".dk": true, |
||||
".dm": true, |
||||
".do": true, |
||||
".dz": true, |
||||
".ec": true, |
||||
".edu": true, |
||||
".ee": true, |
||||
".eg": true, |
||||
".er": true, |
||||
".es": true, |
||||
".et": true, |
||||
".eu": true, |
||||
".fi": true, |
||||
".fj": true, |
||||
".fk": true, |
||||
".fm": true, |
||||
".fo": true, |
||||
".fr": true, |
||||
".ga": true, |
||||
".gb": true, |
||||
".gd": true, |
||||
".ge": true, |
||||
".gf": true, |
||||
".gg": true, |
||||
".gh": true, |
||||
".gi": true, |
||||
".gl": true, |
||||
".gm": true, |
||||
".gn": true, |
||||
".gov": true, |
||||
".gp": true, |
||||
".gq": true, |
||||
".gr": true, |
||||
".gs": true, |
||||
".gt": true, |
||||
".gu": true, |
||||
".gw": true, |
||||
".gy": true, |
||||
".hk": true, |
||||
".hm": true, |
||||
".hn": true, |
||||
".hr": true, |
||||
".ht": true, |
||||
".hu": true, |
||||
".id": true, |
||||
".ie": true, |
||||
".il": true, |
||||
".im": true, |
||||
".in": true, |
||||
".info": true, |
||||
".int": true, |
||||
".io": true, |
||||
".iq": true, |
||||
".ir": true, |
||||
".is": true, |
||||
".it": true, |
||||
".je": true, |
||||
".jm": true, |
||||
".jo": true, |
||||
".jobs": true, |
||||
".jp": true, |
||||
".ke": true, |
||||
".kg": true, |
||||
".kh": true, |
||||
".ki": true, |
||||
".km": true, |
||||
".kn": true, |
||||
".kp": true, |
||||
".kr": true, |
||||
".kw": true, |
||||
".ky": true, |
||||
".kz": true, |
||||
".la": true, |
||||
".lb": true, |
||||
".lc": true, |
||||
".li": true, |
||||
".lk": true, |
||||
".lr": true, |
||||
".ls": true, |
||||
".lt": true, |
||||
".lu": true, |
||||
".lv": true, |
||||
".ly": true, |
||||
".ma": true, |
||||
".mc": true, |
||||
".md": true, |
||||
".me": true, |
||||
".mg": true, |
||||
".mh": true, |
||||
".mil": true, |
||||
".mk": true, |
||||
".ml": true, |
||||
".mm": true, |
||||
".mn": true, |
||||
".mo": true, |
||||
".mobi": true, |
||||
".mp": true, |
||||
".mq": true, |
||||
".mr": true, |
||||
".ms": true, |
||||
".mt": true, |
||||
".mu": true, |
||||
".museum": true, |
||||
".mv": true, |
||||
".mw": true, |
||||
".mx": true, |
||||
".my": true, |
||||
".mz": true, |
||||
".na": true, |
||||
".name": true, |
||||
".nc": true, |
||||
".ne": true, |
||||
".net": true, |
||||
".nf": true, |
||||
".ng": true, |
||||
".ni": true, |
||||
".nl": true, |
||||
".no": true, |
||||
".np": true, |
||||
".nr": true, |
||||
".nu": true, |
||||
".nz": true, |
||||
".om": true, |
||||
".org": true, |
||||
".pa": true, |
||||
".pe": true, |
||||
".pf": true, |
||||
".pg": true, |
||||
".ph": true, |
||||
".pk": true, |
||||
".pl": true, |
||||
".pm": true, |
||||
".pn": true, |
||||
".post": true, |
||||
".pr": true, |
||||
".pro": true, |
||||
".ps": true, |
||||
".pt": true, |
||||
".pw": true, |
||||
".py": true, |
||||
".qa": true, |
||||
".re": true, |
||||
".ro": true, |
||||
".rs": true, |
||||
".ru": true, |
||||
".rw": true, |
||||
".sa": true, |
||||
".sb": true, |
||||
".sc": true, |
||||
".sd": true, |
||||
".se": true, |
||||
".sg": true, |
||||
".sh": true, |
||||
".si": true, |
||||
".sj": true, |
||||
".sk": true, |
||||
".sl": true, |
||||
".sm": true, |
||||
".sn": true, |
||||
".so": true, |
||||
".sr": true, |
||||
".st": true, |
||||
".su": true, |
||||
".sv": true, |
||||
".sx": true, |
||||
".sy": true, |
||||
".sz": true, |
||||
".tc": true, |
||||
".td": true, |
||||
".tel": true, |
||||
".tf": true, |
||||
".tg": true, |
||||
".th": true, |
||||
".tj": true, |
||||
".tk": true, |
||||
".tl": true, |
||||
".tm": true, |
||||
".tn": true, |
||||
".to": true, |
||||
".tp": true, |
||||
".tr": true, |
||||
".travel": true, |
||||
".tt": true, |
||||
".tv": true, |
||||
".tw": true, |
||||
".tz": true, |
||||
".ua": true, |
||||
".ug": true, |
||||
".uk": true, |
||||
".us": true, |
||||
".uy": true, |
||||
".uz": true, |
||||
".va": true, |
||||
".vc": true, |
||||
".ve": true, |
||||
".vg": true, |
||||
".vi": true, |
||||
".vn": true, |
||||
".vu": true, |
||||
".wf": true, |
||||
".ws": true, |
||||
".xn--0zwm56d": true, |
||||
".xn--11b5bs3a9aj6g": true, |
||||
".xn--3e0b707e": true, |
||||
".xn--45brj9c": true, |
||||
".xn--80akhbyknj4f": true, |
||||
".xn--80ao21a": true, |
||||
".xn--90a3ac": true, |
||||
".xn--9t4b11yi5a": true, |
||||
".xn--clchc0ea0b2g2a9gcd": true, |
||||
".xn--deba0ad": true, |
||||
".xn--fiqs8s": true, |
||||
".xn--fiqz9s": true, |
||||
".xn--fpcrj9c3d": true, |
||||
".xn--fzc2c9e2c": true, |
||||
".xn--g6w251d": true, |
||||
".xn--gecrj9c": true, |
||||
".xn--h2brj9c": true, |
||||
".xn--hgbk6aj7f53bba": true, |
||||
".xn--hlcj6aya9esc7a": true, |
||||
".xn--j6w193g": true, |
||||
".xn--jxalpdlp": true, |
||||
".xn--kgbechtv": true, |
||||
".xn--kprw13d": true, |
||||
".xn--kpry57d": true, |
||||
".xn--lgbbat1ad8j": true, |
||||
".xn--mgb9awbf": true, |
||||
".xn--mgbaam7a8h": true, |
||||
".xn--mgbayh7gpa": true, |
||||
".xn--mgbbh1a71e": true, |
||||
".xn--mgbc0a9azcg": true, |
||||
".xn--mgberp4a5d4ar": true, |
||||
".xn--mgbx4cd0ab": true, |
||||
".xn--o3cw4h": true, |
||||
".xn--ogbpf8fl": true, |
||||
".xn--p1ai": true, |
||||
".xn--pgbs0dh": true, |
||||
".xn--s9brj9c": true, |
||||
".xn--wgbh1c": true, |
||||
".xn--wgbl6a": true, |
||||
".xn--xkc2al3hye2a": true, |
||||
".xn--xkc2dl3a5ee0h": true, |
||||
".xn--yfro4i67o": true, |
||||
".xn--ygbi2ammx": true, |
||||
".xn--zckzah": true, |
||||
".xxx": true, |
||||
".ye": true, |
||||
".yt": true, |
||||
".za": true, |
||||
".zm": true, |
||||
".zw": true, |
||||
} |
||||
|
||||
var ( |
||||
validHost = regexp.MustCompile(`^[-a-z0-9]+(?:\.[-a-z0-9]+)+$`) |
||||
validPathElement = regexp.MustCompile(`^[-A-Za-z0-9~+][-A-Za-z0-9_.]*$`) |
||||
) |
||||
|
||||
// IsValidRemotePath returns true if importPath is structurally valid for "go get".
|
||||
func IsValidRemotePath(importPath string) bool { |
||||
|
||||
parts := strings.Split(importPath, "/") |
||||
|
||||
if len(parts) <= 1 { |
||||
// Import path must contain at least one "/".
|
||||
return false |
||||
} |
||||
|
||||
if !validTLD[path.Ext(parts[0])] { |
||||
return false |
||||
} |
||||
|
||||
if !validHost.MatchString(parts[0]) { |
||||
return false |
||||
} |
||||
for _, part := range parts[1:] { |
||||
if !validPathElement.MatchString(part) || part == "testdata" { |
||||
return false |
||||
} |
||||
} |
||||
|
||||
return true |
||||
} |
||||
|
||||
var standardPath = map[string]bool{ |
||||
"builtin": true, |
||||
|
||||
// go list -f '"{{.ImportPath}}": true,' std | grep -v 'cmd/|exp/'
|
||||
"cmd/api": true, |
||||
"cmd/cgo": true, |
||||
"cmd/fix": true, |
||||
"cmd/go": true, |
||||
"cmd/gofmt": true, |
||||
"cmd/vet": true, |
||||
"cmd/yacc": true, |
||||
"archive/tar": true, |
||||
"archive/zip": true, |
||||
"bufio": true, |
||||
"bytes": true, |
||||
"compress/bzip2": true, |
||||
"compress/flate": true, |
||||
"compress/gzip": true, |
||||
"compress/lzw": true, |
||||
"compress/zlib": true, |
||||
"container/heap": true, |
||||
"container/list": true, |
||||
"container/ring": true, |
||||
"crypto": true, |
||||
"crypto/aes": true, |
||||
"crypto/cipher": true, |
||||
"crypto/des": true, |
||||
"crypto/dsa": true, |
||||
"crypto/ecdsa": true, |
||||
"crypto/elliptic": true, |
||||
"crypto/hmac": true, |
||||
"crypto/md5": true, |
||||
"crypto/rand": true, |
||||
"crypto/rc4": true, |
||||
"crypto/rsa": true, |
||||
"crypto/sha1": true, |
||||
"crypto/sha256": true, |
||||
"crypto/sha512": true, |
||||
"crypto/subtle": true, |
||||
"crypto/tls": true, |
||||
"crypto/x509": true, |
||||
"crypto/x509/pkix": true, |
||||
"database/sql": true, |
||||
"database/sql/driver": true, |
||||
"debug/dwarf": true, |
||||
"debug/elf": true, |
||||
"debug/gosym": true, |
||||
"debug/macho": true, |
||||
"debug/pe": true, |
||||
"encoding/ascii85": true, |
||||
"encoding/asn1": true, |
||||
"encoding/base32": true, |
||||
"encoding/base64": true, |
||||
"encoding/binary": true, |
||||
"encoding/csv": true, |
||||
"encoding/gob": true, |
||||
"encoding/hex": true, |
||||
"encoding/json": true, |
||||
"encoding/pem": true, |
||||
"encoding/xml": true, |
||||
"errors": true, |
||||
"expvar": true, |
||||
"flag": true, |
||||
"fmt": true, |
||||
"go/ast": true, |
||||
"go/build": true, |
||||
"go/doc": true, |
||||
"go/format": true, |
||||
"go/parser": true, |
||||
"go/printer": true, |
||||
"go/scanner": true, |
||||
"go/token": true, |
||||
"hash": true, |
||||
"hash/adler32": true, |
||||
"hash/crc32": true, |
||||
"hash/crc64": true, |
||||
"hash/fnv": true, |
||||
"html": true, |
||||
"html/template": true, |
||||
"image": true, |
||||
"image/color": true, |
||||
"image/draw": true, |
||||
"image/gif": true, |
||||
"image/jpeg": true, |
||||
"image/png": true, |
||||
"index/suffixarray": true, |
||||
"io": true, |
||||
"io/ioutil": true, |
||||
"log": true, |
||||
"log/syslog": true, |
||||
"math": true, |
||||
"math/big": true, |
||||
"math/cmplx": true, |
||||
"math/rand": true, |
||||
"mime": true, |
||||
"mime/multipart": true, |
||||
"net": true, |
||||
"net/http": true, |
||||
"net/http/cgi": true, |
||||
"net/http/cookiejar": true, |
||||
"net/http/fcgi": true, |
||||
"net/http/httptest": true, |
||||
"net/http/httputil": true, |
||||
"net/http/pprof": true, |
||||
"net/mail": true, |
||||
"net/rpc": true, |
||||
"net/rpc/jsonrpc": true, |
||||
"net/smtp": true, |
||||
"net/textproto": true, |
||||
"net/url": true, |
||||
"os": true, |
||||
"os/exec": true, |
||||
"os/signal": true, |
||||
"os/user": true, |
||||
"path": true, |
||||
"path/filepath": true, |
||||
"reflect": true, |
||||
"regexp": true, |
||||
"regexp/syntax": true, |
||||
"runtime": true, |
||||
"runtime/cgo": true, |
||||
"runtime/debug": true, |
||||
"runtime/pprof": true, |
||||
"runtime/race": true, |
||||
"sort": true, |
||||
"strconv": true, |
||||
"strings": true, |
||||
"sync": true, |
||||
"sync/atomic": true, |
||||
"syscall": true, |
||||
"testing": true, |
||||
"testing/iotest": true, |
||||
"testing/quick": true, |
||||
"text/scanner": true, |
||||
"text/tabwriter": true, |
||||
"text/template": true, |
||||
"text/template/parse": true, |
||||
"time": true, |
||||
"unicode": true, |
||||
"unicode/utf16": true, |
||||
"unicode/utf8": true, |
||||
"unsafe": true, |
||||
} |
||||
|
||||
// IsGoRepoPath returns true if package is from standard library.
|
||||
func IsGoRepoPath(importPath string) bool { |
||||
return standardPath[importPath] |
||||
} |
||||
|
||||
func CheckNodeValue(v string) string { |
||||
if len(v) == 0 { |
||||
return "<UTD>" |
||||
} |
||||
return v |
||||
} |
@ -0,0 +1,71 @@
|
||||
// Copyright 2013-2014 gopm authors.
|
||||
//
|
||||
// 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.
|
||||
|
||||
package doc |
||||
|
||||
import ( |
||||
"testing" |
||||
|
||||
. "github.com/smartystreets/goconvey/convey" |
||||
) |
||||
|
||||
var VcsTestPairs = map[string]bool{ |
||||
"/.hg": true, |
||||
"/.git": true, |
||||
"/.svn": true, |
||||
"/.vendor": false, |
||||
} |
||||
|
||||
func Test_isVcsPath(t *testing.T) { |
||||
Convey("Test if the path is belonging to VCS", t, func() { |
||||
for name, expect := range VcsTestPairs { |
||||
So(isVcsPath(name), ShouldEqual, expect) |
||||
} |
||||
}) |
||||
} |
||||
|
||||
func TestGetDirsInfo(t *testing.T) { |
||||
Convey("Get directory's information that exist", t, func() { |
||||
dis, err := GetDirsInfo(".") |
||||
So(err, ShouldBeNil) |
||||
So(len(dis), ShouldEqual, 13) |
||||
}) |
||||
|
||||
Convey("Get directory's information does not exist", t, func() { |
||||
dis, err := GetDirsInfo("./404") |
||||
So(err, ShouldBeNil) |
||||
So(len(dis), ShouldEqual, 0) |
||||
}) |
||||
} |
||||
|
||||
var GoStdTestPairs = map[string]bool{ |
||||
"net/http": true, |
||||
"fmt": true, |
||||
"github.com/gpmgo/gopm": false, |
||||
"github.com/Unknwon/com": false, |
||||
} |
||||
|
||||
func TestIsGoRepoPath(t *testing.T) { |
||||
Convey("Test if the path is belonging to Go STD", t, func() { |
||||
for name, expect := range GoStdTestPairs { |
||||
So(IsGoRepoPath(name), ShouldEqual, expect) |
||||
} |
||||
}) |
||||
} |
||||
|
||||
func TestGetImports(t *testing.T) { |
||||
Convey("Get package that are imported", t, func() { |
||||
So(len(GetImports(".", "github.com/gpmgo/gopm/docs", false)), ShouldEqual, 4) |
||||
}) |
||||
} |
@ -0,0 +1,307 @@
|
||||
// Copyright 2013-2014 gopm authors.
|
||||
//
|
||||
// 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.
|
||||
|
||||
package doc |
||||
|
||||
import ( |
||||
"encoding/xml" |
||||
"errors" |
||||
"io" |
||||
"net/http" |
||||
"os" |
||||
"path" |
||||
"regexp" |
||||
"strings" |
||||
|
||||
"github.com/Unknwon/com" |
||||
"github.com/codegangsta/cli" |
||||
"github.com/gpmgo/gopm/log" |
||||
) |
||||
|
||||
var ( |
||||
appPath string |
||||
autoBackup bool |
||||
) |
||||
|
||||
func SetAppConfig(path string, backup bool) { |
||||
appPath = path |
||||
autoBackup = backup |
||||
} |
||||
|
||||
// TODO: specify with command line flag
|
||||
const repoRoot = "/tmp/gddo" |
||||
|
||||
var urlTemplates = []struct { |
||||
re *regexp.Regexp |
||||
template string |
||||
lineFmt string |
||||
}{ |
||||
{ |
||||
regexp.MustCompile(`^git\.gitorious\.org/(?P<repo>[^/]+/[^/]+)$`), |
||||
"https://gitorious.org/{repo}/blobs/{tag}/{dir}{0}", |
||||
"#line%d", |
||||
}, |
||||
{ |
||||
regexp.MustCompile(`^camlistore\.org/r/p/(?P<repo>[^/]+)$`), |
||||
"http://camlistore.org/code/?p={repo}.git;hb={tag};f={dir}{0}", |
||||
"#l%d", |
||||
}, |
||||
} |
||||
|
||||
// lookupURLTemplate finds an expand() template, match map and line number
|
||||
// format for well known repositories.
|
||||
func lookupURLTemplate(repo, dir, tag string) (string, map[string]string, string) { |
||||
if strings.HasPrefix(dir, "/") { |
||||
dir = dir[1:] + "/" |
||||
} |
||||
for _, t := range urlTemplates { |
||||
if m := t.re.FindStringSubmatch(repo); m != nil { |
||||
match := map[string]string{ |
||||
"dir": dir, |
||||
"tag": tag, |
||||
} |
||||
for i, name := range t.re.SubexpNames() { |
||||
if name != "" { |
||||
match[name] = m[i] |
||||
} |
||||
} |
||||
return t.template, match, t.lineFmt |
||||
} |
||||
} |
||||
return "", nil, "" |
||||
} |
||||
|
||||
type vcsCmd struct { |
||||
schemes []string |
||||
download func([]string, string, string) (string, string, error) |
||||
} |
||||
|
||||
var lsremoteRe = regexp.MustCompile(`(?m)^([0-9a-f]{40})\s+refs/(?:tags|heads)/(.+)$`) |
||||
|
||||
var defaultTags = map[string]string{"git": "master", "hg": "default"} |
||||
|
||||
func bestTag(tags map[string]string, defaultTag string) (string, string, error) { |
||||
if commit, ok := tags[defaultTag]; ok { |
||||
return defaultTag, commit, nil |
||||
} |
||||
return "", "", com.NotFoundError{"Tag or branch not found."} |
||||
} |
||||
|
||||
// PureDownload downloads package without version control.
|
||||
func PureDownload(nod *Node, installRepoPath string, ctx *cli.Context) ([]string, error) { |
||||
for _, s := range services { |
||||
if s.get == nil || !strings.HasPrefix(nod.DownloadURL, s.prefix) { |
||||
continue |
||||
} |
||||
m := s.pattern.FindStringSubmatch(nod.DownloadURL) |
||||
if m == nil { |
||||
if s.prefix != "" { |
||||
return nil, errors.New("Cannot match package service prefix by given path") |
||||
} |
||||
continue |
||||
} |
||||
match := map[string]string{"importPath": nod.DownloadURL} |
||||
for i, n := range s.pattern.SubexpNames() { |
||||
if n != "" { |
||||
match[n] = m[i] |
||||
} |
||||
} |
||||
return s.get(HttpClient, match, installRepoPath, nod, ctx) |
||||
} |
||||
|
||||
log.Log("Cannot match any service, getting dynamic...") |
||||
return getDynamic(HttpClient, nod, installRepoPath, ctx) |
||||
} |
||||
|
||||
func getDynamic(client *http.Client, nod *Node, installRepoPath string, ctx *cli.Context) ([]string, error) { |
||||
match, err := fetchMeta(client, nod.ImportPath) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
if match["projectRoot"] != nod.ImportPath { |
||||
rootMatch, err := fetchMeta(client, match["projectRoot"]) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
if rootMatch["projectRoot"] != match["projectRoot"] { |
||||
return nil, com.NotFoundError{"Project root mismatch."} |
||||
} |
||||
} |
||||
|
||||
nod.DownloadURL = com.Expand("{repo}{dir}", match) |
||||
return PureDownload(nod, installRepoPath, ctx) |
||||
} |
||||
|
||||
func fetchMeta(client *http.Client, importPath string) (map[string]string, error) { |
||||
uri := importPath |
||||
if !strings.Contains(uri, "/") { |
||||
// Add slash for root of domain.
|
||||
uri = uri + "/" |
||||
} |
||||
uri = uri + "?go-get=1" |
||||
|
||||
scheme := "https" |
||||
resp, err := client.Get(scheme + "://" + uri) |
||||
if err != nil || resp.StatusCode != 200 { |
||||
if err == nil { |
||||
resp.Body.Close() |
||||
} |
||||
scheme = "http" |
||||
resp, err = client.Get(scheme + "://" + uri) |
||||
if err != nil { |
||||
return nil, &com.RemoteError{strings.SplitN(importPath, "/", 2)[0], err} |
||||
} |
||||
} |
||||
defer resp.Body.Close() |
||||
return parseMeta(scheme, importPath, resp.Body) |
||||
} |
||||
|
||||
func attrValue(attrs []xml.Attr, name string) string { |
||||
for _, a := range attrs { |
||||
if strings.EqualFold(a.Name.Local, name) { |
||||
return a.Value |
||||
} |
||||
} |
||||
return "" |
||||
} |
||||
|
||||
func parseMeta(scheme, importPath string, r io.Reader) (map[string]string, error) { |
||||
var match map[string]string |
||||
|
||||
d := xml.NewDecoder(r) |
||||
d.Strict = false |
||||
metaScan: |
||||
for { |
||||
t, tokenErr := d.Token() |
||||
if tokenErr != nil { |
||||
break metaScan |
||||
} |
||||
switch t := t.(type) { |
||||
case xml.EndElement: |
||||
if strings.EqualFold(t.Name.Local, "head") { |
||||
break metaScan |
||||
} |
||||
case xml.StartElement: |
||||
if strings.EqualFold(t.Name.Local, "body") { |
||||
break metaScan |
||||
} |
||||
if !strings.EqualFold(t.Name.Local, "meta") || |
||||
attrValue(t.Attr, "name") != "go-import" { |
||||
continue metaScan |
||||
} |
||||
f := strings.Fields(attrValue(t.Attr, "content")) |
||||
if len(f) != 3 || |
||||
!strings.HasPrefix(importPath, f[0]) || |
||||
!(len(importPath) == len(f[0]) || importPath[len(f[0])] == '/') { |
||||
continue metaScan |
||||
} |
||||
if match != nil { |
||||
return nil, com.NotFoundError{"More than one <meta> found at " + scheme + "://" + importPath} |
||||
} |
||||
|
||||
projectRoot, vcs, repo := f[0], f[1], f[2] |
||||
|
||||
repo = strings.TrimSuffix(repo, "."+vcs) |
||||
i := strings.Index(repo, "://") |
||||
if i < 0 { |
||||
return nil, com.NotFoundError{"Bad repo URL in <meta>."} |
||||
} |
||||
proto := repo[:i] |
||||
repo = repo[i+len("://"):] |
||||
|
||||
match = map[string]string{ |
||||
// Used in getVCSDoc, same as vcsPattern matches.
|
||||
"importPath": importPath, |
||||
"repo": repo, |
||||
"vcs": vcs, |
||||
"dir": importPath[len(projectRoot):], |
||||
|
||||
// Used in getVCSDoc
|
||||
"scheme": proto, |
||||
|
||||
// Used in getDynamic.
|
||||
"projectRoot": projectRoot, |
||||
"projectName": path.Base(projectRoot), |
||||
"projectURL": scheme + "://" + projectRoot, |
||||
} |
||||
} |
||||
} |
||||
if match == nil { |
||||
return nil, com.NotFoundError{"<meta> not found."} |
||||
} |
||||
return match, nil |
||||
} |
||||
|
||||
func getImports(rootPath string, match map[string]string, cmdFlags map[string]bool, nod *Node) (imports []string) { |
||||
dirs, err := GetDirsInfo(rootPath) |
||||
if err != nil { |
||||
log.Error("", "Fail to get directory's information") |
||||
log.Fatal("", err.Error()) |
||||
} |
||||
|
||||
for _, d := range dirs { |
||||
if d.IsDir() && !(!cmdFlags["-e"] && strings.Contains(d.Name(), "example")) { |
||||
absPath := rootPath + d.Name() + "/" |
||||
importPkgs, err := CheckImports(absPath, match["importPath"], nod) |
||||
if err != nil { |
||||
return nil |
||||
} |
||||
imports = append(imports, importPkgs...) |
||||
} |
||||
} |
||||
return imports |
||||
} |
||||
|
||||
// checkImports checks package denpendencies.
|
||||
func CheckImports(absPath, importPath string, nod *Node) (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") { |
||||
data, err := com.ReadFile(absPath + fi.Name()) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
files = append(files, &source{ |
||||
name: fi.Name(), |
||||
data: data, |
||||
}) |
||||
} |
||||
} |
||||
|
||||
// Check if has Go source files.
|
||||
if len(files) > 0 { |
||||
w := &walker{ImportPath: importPath} |
||||
importPkgs, err = w.build(files, nod) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
} |
||||
|
||||
return importPkgs, err |
||||
} |
@ -0,0 +1,239 @@
|
||||
// Copyright 2013 gopm authors.
|
||||
//
|
||||
// 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.
|
||||
|
||||
package doc |
||||
|
||||
import ( |
||||
"bytes" |
||||
"go/ast" |
||||
"go/build" |
||||
"go/doc" |
||||
"go/parser" |
||||
"go/token" |
||||
"io" |
||||
"io/ioutil" |
||||
"os" |
||||
"path" |
||||
"runtime" |
||||
"strings" |
||||
"unicode" |
||||
"unicode/utf8" |
||||
|
||||
"github.com/gpmgo/gopm/log" |
||||
) |
||||
|
||||
type sliceWriter struct{ p *[]byte } |
||||
|
||||
func (w sliceWriter) Write(p []byte) (int, error) { |
||||
*w.p = append(*w.p, p...) |
||||
return len(p), nil |
||||
} |
||||
|
||||
func (w *walker) readDir(dir string) ([]os.FileInfo, error) { |
||||
if dir != w.ImportPath { |
||||
panic("unexpected") |
||||
} |
||||
fis := make([]os.FileInfo, 0, len(w.srcs)) |
||||
for _, src := range w.srcs { |
||||
fis = append(fis, src) |
||||
} |
||||
return fis, nil |
||||
} |
||||
|
||||
func (w *walker) openFile(path string) (io.ReadCloser, error) { |
||||
if strings.HasPrefix(path, w.ImportPath+"/") { |
||||
if src, ok := w.srcs[path[len(w.ImportPath)+1:]]; ok { |
||||
return ioutil.NopCloser(bytes.NewReader(src.data)), nil |
||||
} |
||||
} |
||||
panic("unexpected") |
||||
} |
||||
|
||||
func simpleImporter(imports map[string]*ast.Object, path string) (*ast.Object, error) { |
||||
pkg := imports[path] |
||||
if pkg == nil { |
||||
// Guess the package name without importing it. Start with the last
|
||||
// element of the path.
|
||||
name := path[strings.LastIndex(path, "/")+1:] |
||||
|
||||
// Trim commonly used prefixes and suffixes containing illegal name
|
||||
// runes.
|
||||
name = strings.TrimSuffix(name, ".go") |
||||
name = strings.TrimSuffix(name, "-go") |
||||
name = strings.TrimPrefix(name, "go.") |
||||
name = strings.TrimPrefix(name, "go-") |
||||
name = strings.TrimPrefix(name, "biogo.") |
||||
|
||||
// It's also common for the last element of the path to contain an
|
||||
// extra "go" prefix, but not always. TODO: examine unresolved ids to
|
||||
// detect when trimming the "go" prefix is appropriate.
|
||||
|
||||
pkg = ast.NewObj(ast.Pkg, name) |
||||
pkg.Data = ast.NewScope(nil) |
||||
imports[path] = pkg |
||||
} |
||||
return pkg, nil |
||||
} |
||||
|
||||
// build gets imports from source files.
|
||||
func (w *walker) build(srcs []*source, nod *Node) ([]string, error) { |
||||
// Add source files to walker, I skipped references here.
|
||||
w.srcs = make(map[string]*source) |
||||
for _, src := range srcs { |
||||
w.srcs[src.name] = src |
||||
} |
||||
|
||||
w.fset = token.NewFileSet() |
||||
|
||||
// Find the package and associated files.
|
||||
ctxt := build.Context{ |
||||
GOOS: runtime.GOOS, |
||||
GOARCH: runtime.GOARCH, |
||||
CgoEnabled: true, |
||||
JoinPath: path.Join, |
||||
IsAbsPath: path.IsAbs, |
||||
SplitPathList: func(list string) []string { return strings.Split(list, ":") }, |
||||
IsDir: func(path string) bool { panic("unexpected") }, |
||||
HasSubdir: func(root, dir string) (rel string, ok bool) { panic("unexpected") }, |
||||
ReadDir: func(dir string) (fi []os.FileInfo, err error) { return w.readDir(dir) }, |
||||
OpenFile: func(path string) (r io.ReadCloser, err error) { return w.openFile(path) }, |
||||
Compiler: "gc", |
||||
} |
||||
|
||||
bpkg, err := ctxt.ImportDir(w.ImportPath, 0) |
||||
// Continue if there are no Go source files; we still want the directory info.
|
||||
_, nogo := err.(*build.NoGoError) |
||||
if err != nil { |
||||
if nogo { |
||||
err = nil |
||||
} else { |
||||
log.Warn("walker: %s", err.Error()) |
||||
return nil, nil |
||||
} |
||||
} |
||||
|
||||
// Parse the Go files
|
||||
|
||||
files := make(map[string]*ast.File) |
||||
for _, name := range append(bpkg.GoFiles, bpkg.CgoFiles...) { |
||||
file, err := parser.ParseFile(w.fset, name, w.srcs[name].data, parser.ParseComments) |
||||
if err != nil { |
||||
//beego.Error("doc.walker.build():", err)
|
||||
continue |
||||
} |
||||
files[name] = file |
||||
} |
||||
|
||||
w.ImportPath = strings.Replace(w.ImportPath, "\\", "/", -1) |
||||
var imports []string |
||||
for _, v := range bpkg.Imports { |
||||
// Skip strandard library.
|
||||
if !IsGoRepoPath(v) && |
||||
(GetProjectPath(v) != GetProjectPath(w.ImportPath)) { |
||||
imports = append(imports, v) |
||||
} |
||||
} |
||||
|
||||
apkg, _ := ast.NewPackage(w.fset, files, simpleImporter, nil) |
||||
|
||||
mode := doc.Mode(0) |
||||
if w.ImportPath == "builtin" { |
||||
mode |= doc.AllDecls |
||||
} |
||||
|
||||
pdoc := doc.New(apkg, w.ImportPath, mode) |
||||
|
||||
if nod != nil { |
||||
nod.Synopsis = Synopsis(pdoc.Doc) |
||||
if i := strings.Index(nod.Synopsis, "\n"); i > -1 { |
||||
nod.Synopsis = nod.Synopsis[:i] |
||||
} |
||||
} |
||||
|
||||
return imports, err |
||||
} |
||||
|
||||
var badSynopsisPrefixes = []string{ |
||||
"Autogenerated by Thrift Compiler", |
||||
"Automatically generated ", |
||||
"Auto-generated by ", |
||||
"Copyright ", |
||||
"COPYRIGHT ", |
||||
`THE SOFTWARE IS PROVIDED "AS IS"`, |
||||
"TODO: ", |
||||
"vim:", |
||||
} |
||||
|
||||
// Synopsis extracts the first sentence from s. All runs of whitespace are
|
||||
// replaced by a single space.
|
||||
func Synopsis(s string) string { |
||||
|
||||
parts := strings.SplitN(s, "\n\n", 2) |
||||
s = parts[0] |
||||
|
||||
var buf []byte |
||||
const ( |
||||
other = iota |
||||
period |
||||
space |
||||
) |
||||
last := space |
||||
Loop: |
||||
for i := 0; i < len(s); i++ { |
||||
b := s[i] |
||||
switch b { |
||||
case ' ', '\t', '\r', '\n': |
||||
switch last { |
||||
case period: |
||||
break Loop |
||||
case other: |
||||
buf = append(buf, ' ') |
||||
last = space |
||||
} |
||||
case '.': |
||||
last = period |
||||
buf = append(buf, b) |
||||
default: |
||||
last = other |
||||
buf = append(buf, b) |
||||
} |
||||
} |
||||
|
||||
// Ensure that synopsis fits an App Engine datastore text property.
|
||||
const m = 400 |
||||
if len(buf) > m { |
||||
buf = buf[:m] |
||||
if i := bytes.LastIndex(buf, []byte{' '}); i >= 0 { |
||||
buf = buf[:i] |
||||
} |
||||
buf = append(buf, " ..."...) |
||||
} |
||||
|
||||
s = string(buf) |
||||
|
||||
r, n := utf8.DecodeRuneInString(s) |
||||
if n < 0 || unicode.IsPunct(r) || unicode.IsSymbol(r) { |
||||
// ignore Markdown headings, editor settings, Go build constraints, and * in poorly formatted block comments.
|
||||
s = "" |
||||
} else { |
||||
for _, prefix := range badSynopsisPrefixes { |
||||
if strings.HasPrefix(s, prefix) { |
||||
s = "" |
||||
break |
||||
} |
||||
} |
||||
} |
||||
|
||||
return s |
||||
} |
@ -0,0 +1,67 @@
|
||||
// Copyright 2013-2014 gopm authors.
|
||||
//
|
||||
// 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.
|
||||
|
||||
// gopm(Go Package Manager) is a Go package manage tool for searching, installing, updating and sharing your packages in Go.
|
||||
package main |
||||
|
||||
import ( |
||||
"os" |
||||
"runtime" |
||||
|
||||
"github.com/codegangsta/cli" |
||||
|
||||
"github.com/gpmgo/gopm/cmd" |
||||
) |
||||
|
||||
// +build go1.1
|
||||
|
||||
// Test that go1.1 tag above is included in builds. main.go refers to this definition.
|
||||
const go11tag = true |
||||
|
||||
const APP_VER = "0.6.5.0320" |
||||
|
||||
// cmd.CmdTest,
|
||||
// cmd.CmdSearch,
|
||||
// cmdClean,
|
||||
// cmdDoc,
|
||||
// cmdEnv,
|
||||
// cmdFix,
|
||||
// cmdList,
|
||||
// cmdTool,
|
||||
// cmdVet,
|
||||
|
||||
func init() { |
||||
runtime.GOMAXPROCS(runtime.NumCPU()) |
||||
} |
||||
|
||||
func main() { |
||||
app := cli.NewApp() |
||||
app.Name = "gopm" |
||||
app.Usage = "Go Package Manager" |
||||
app.Version = APP_VER |
||||
app.Commands = []cli.Command{ |
||||
cmd.CmdGet, |
||||
cmd.CmdBin, |
||||
cmd.CmdGen, |
||||
cmd.CmdRun, |
||||
cmd.CmdBuild, |
||||
cmd.CmdInstall, |
||||
cmd.CmdUpdate, |
||||
cmd.CmdConfig, |
||||
} |
||||
app.Flags = append(app.Flags, []cli.Flag{ |
||||
cli.BoolFlag{"noterm", "disable color output"}, |
||||
}...) |
||||
app.Run(os.Args) |
||||
} |
@ -0,0 +1,121 @@
|
||||
// Copyright 2013 gopm authors.
|
||||
//
|
||||
// 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.
|
||||
|
||||
// +build !windows
|
||||
|
||||
// Package log provides npm-like style log output.
|
||||
package log |
||||
|
||||
import ( |
||||
"fmt" |
||||
"os" |
||||
|
||||
"github.com/aybabtme/color/brush" |
||||
) |
||||
|
||||
func Error(hl, msg string) { |
||||
if PureMode { |
||||
errorP(hl, msg) |
||||
} |
||||
|
||||
if len(hl) > 0 { |
||||
hl = " " + brush.Red(hl).String() |
||||
} |
||||
fmt.Printf("gopm %s%s %s\n", brush.Red("ERR!"), hl, msg) |
||||
} |
||||
|
||||
func Fatal(hl, msg string) { |
||||
if PureMode { |
||||
fatal(hl, msg) |
||||
} |
||||
|
||||
Error(hl, msg) |
||||
os.Exit(2) |
||||
} |
||||
|
||||
func Warn(format string, args ...interface{}) { |
||||
if PureMode { |
||||
warn(format, args...) |
||||
return |
||||
} |
||||
|
||||
fmt.Printf("gopm %s %s\n", brush.Purple("WARN"), |
||||
fmt.Sprintf(format, args...)) |
||||
} |
||||
|
||||
func Log(format string, args ...interface{}) { |
||||
if PureMode { |
||||
log(format, args...) |
||||
return |
||||
} |
||||
|
||||
if !Verbose { |
||||
return |
||||
} |
||||
fmt.Printf("gopm %s %s\n", brush.White("INFO"), |
||||
fmt.Sprintf(format, args...)) |
||||
} |
||||
|
||||
func Trace(format string, args ...interface{}) { |
||||
if PureMode { |
||||
trace(format, args...) |
||||
return |
||||
} |
||||
|
||||
if !Verbose { |
||||
return |
||||
} |
||||
fmt.Printf("gopm %s %s\n", brush.Blue("TRAC"), |
||||
fmt.Sprintf(format, args...)) |
||||
} |
||||
|
||||
func Success(title, hl, msg string) { |
||||
if PureMode { |
||||
success(title, hl, msg) |
||||
return |
||||
} |
||||
|
||||
if !Verbose { |
||||
return |
||||
} |
||||
if len(hl) > 0 { |
||||
hl = " " + brush.Green(hl).String() |
||||
} |
||||
fmt.Printf("gopm %s%s %s\n", brush.Green(title), hl, msg) |
||||
} |
||||
|
||||
func Message(hl, msg string) { |
||||
if PureMode { |
||||
message(hl, msg) |
||||
return |
||||
} |
||||
|
||||
if !Verbose { |
||||
return |
||||
} |
||||
if len(hl) > 0 { |
||||
hl = " " + brush.Yellow(hl).String() |
||||
} |
||||
fmt.Printf("gopm %s%s %s\n", brush.Yellow("MSG!"), hl, msg) |
||||
} |
||||
|
||||
func Help(format string, args ...interface{}) { |
||||
if PureMode { |
||||
help(format, args...) |
||||
} |
||||
|
||||
fmt.Printf("gopm %s %s\n", brush.Cyan("HELP"), |
||||
fmt.Sprintf(format, args...)) |
||||
os.Exit(2) |
||||
} |
@ -0,0 +1,80 @@
|
||||
// Copyright 2013 gopm authors.
|
||||
//
|
||||
// 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.
|
||||
|
||||
package log |
||||
|
||||
import ( |
||||
"fmt" |
||||
"os" |
||||
) |
||||
|
||||
var ( |
||||
PureMode = false |
||||
Verbose = false |
||||
) |
||||
|
||||
func errorP(hl, msg string) { |
||||
if len(hl) > 0 { |
||||
hl = " " + hl |
||||
} |
||||
fmt.Printf("gopm ERR!%s %s\n", hl, msg) |
||||
} |
||||
|
||||
func fatal(hl, msg string) { |
||||
errorP(hl, msg) |
||||
os.Exit(2) |
||||
} |
||||
|
||||
func warn(format string, args ...interface{}) { |
||||
fmt.Printf("gopm WARN %s\n", fmt.Sprintf(format, args...)) |
||||
} |
||||
|
||||
func log(format string, args ...interface{}) { |
||||
if !Verbose { |
||||
return |
||||
} |
||||
fmt.Printf("gopm INFO %s\n", fmt.Sprintf(format, args...)) |
||||
} |
||||
|
||||
func trace(format string, args ...interface{}) { |
||||
if !Verbose { |
||||
return |
||||
} |
||||
fmt.Printf("gopm TRAC %s\n", fmt.Sprintf(format, args...)) |
||||
} |
||||
|
||||
func success(title, hl, msg string) { |
||||
if !Verbose { |
||||
return |
||||
} |
||||
if len(hl) > 0 { |
||||
hl = " " + hl |
||||
} |
||||
fmt.Printf("gopm %s%s %s\n", title, hl, msg) |
||||
} |
||||
|
||||
func message(hl, msg string) { |
||||
if !Verbose { |
||||
return |
||||
} |
||||
if len(hl) > 0 { |
||||
hl = " " + hl |
||||
} |
||||
fmt.Printf("gopm MSG!%s %s\n", hl, msg) |
||||
} |
||||
|
||||
func help(format string, args ...interface{}) { |
||||
fmt.Printf("gopm HELP %s\n", fmt.Sprintf(format, args...)) |
||||
os.Exit(2) |
||||
} |
@ -0,0 +1,48 @@
|
||||
// Copyright 2013 gopm authors.
|
||||
//
|
||||
// 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.
|
||||
|
||||
// Package log provides npm-like style log output.
|
||||
package log |
||||
|
||||
func Error(hl, msg string) { |
||||
errorP(hl, msg) |
||||
} |
||||
|
||||
func Fatal(hl, msg string) { |
||||
fatal(hl, msg) |
||||
} |
||||
|
||||
func Warn(format string, args ...interface{}) { |
||||
warn(format, args...) |
||||
} |
||||
|
||||
func Log(format string, args ...interface{}) { |
||||
log(format, args...) |
||||
} |
||||
|
||||
func Trace(format string, args ...interface{}) { |
||||
trace(format, args...) |
||||
} |
||||
|
||||
func Success(title, hl, msg string) { |
||||
success(title, hl, msg) |
||||
} |
||||
|
||||
func Message(hl, msg string) { |
||||
message(hl, msg) |
||||
} |
||||
|
||||
func Help(format string, args ...interface{}) { |
||||
help(format, args...) |
||||
} |
Loading…
Reference in new issue