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") } } }
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) }
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 = 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) default: getByPath(ctx) } }
// 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 }
// 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 } if err = com.WriteFile(absPath, fbytes); 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 }
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")) } 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!") }
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) }
// 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 }
func runGet(ctx *cli.Context) { setup(ctx) // Check conflicts. if ctx.Bool("gopath") && ctx.Bool("remote") || ctx.Bool("local") && ctx.Bool("remote") || ctx.Bool("gopath") && ctx.Bool("local") { e := " " if ctx.Bool("gopath") { e += "--gopth,-g " } if ctx.Bool("remote") { e += "--remote,-r " } if ctx.Bool("local") { e += "--local,-l " } log.Error("get", "Command options have conflicts") log.Error("", "Following options are not supposed to use at same time:") log.Error("", "\t"+e) 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") } } // if flag local set use localPath as GOPATH if ctx.Bool("local") { if !com.IsExist(".gopmfile") { runGen(ctx) } gf, err := goconfig.LoadConfigFile(".gopmfile") if err != nil { log.Fatal("get", err.Error()) } else { installGopath = gf.MustValue("project", "localPath") if installGopath == "" { os.Remove(".gopmfile") log.Fatal("get", "unexpected localPath or no localPath exists") } installGopath += "/src" } } } // 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") } }