func getByPaths(ctx *cli.Context) error { nodes := make([]*doc.Node, 0, len(ctx.Args())) for _, info := range ctx.Args() { pkgPath := info n := doc.NewNode(pkgPath, doc.BRANCH, "", !ctx.Bool("download")) if i := strings.Index(info, "@"); i > -1 { pkgPath = info[:i] tp, val, err := validPkgInfo(info[i+1:]) if err != nil { return err } n = doc.NewNode(pkgPath, tp, val, !ctx.Bool("download")) } // Check package name. if !strings.Contains(pkgPath, "/") { tmpPath, err := setting.GetPkgFullPath(pkgPath) if err != nil { return err } if tmpPath != pkgPath { n = doc.NewNode(tmpPath, n.Type, n.Value, n.IsGetDeps) } } nodes = append(nodes, n) } return getPackages(".", ctx, nodes) }
func getByGopmfile(ctx *cli.Context) error { // Make sure gopmfile exists and up-to-date. gf, target, err := parseGopmfile(setting.GOPMFILE) if err != nil { return err } imports, err := getDepList(ctx, target, setting.WorkDir, setting.DefaultVendor) if err != nil { return err } // Check if dependency has version. nodes := make([]*doc.Node, 0, len(imports)) for _, name := range imports { name = doc.GetRootPath(name) n := doc.NewNode(name, doc.BRANCH, "", !ctx.Bool("download")) // Check if user specified the version. if v := gf.MustValue("deps", name); len(v) > 0 { n.Type, n.Value, err = validPkgInfo(v) n = doc.NewNode(name, n.Type, n.Value, !ctx.Bool("download")) } nodes = append(nodes, n) } return getPackages(target, ctx, nodes) }
func runClean(ctx *cli.Context) { if err := setup(ctx); err != nil { errors.SetError(err) return } os.RemoveAll(path.Join(setting.HomeDir, ".gopm/temp")) if ctx.Bool("all") { os.RemoveAll(setting.InstallRepoPath) } }
func runInstall(ctx *cli.Context) { if err := setup(ctx); err != nil { errors.SetError(err) return } os.RemoveAll(setting.DefaultVendor) if !setting.Debug { defer os.RemoveAll(setting.DefaultVendor) } if err := linkVendors(ctx, ""); err != nil { errors.SetError(err) return } // Get target name. gfPath := path.Join(setting.WorkDir, setting.GOPMFILE) _, target, err := parseGopmfile(gfPath) if err != nil { errors.SetError(fmt.Errorf("fail to parse gopmfile: %v", err)) return } log.Info("Installing...") cmdArgs := []string{"go", "install"} if ctx.Bool("verbose") { cmdArgs = append(cmdArgs, "-v") } cmdArgs = append(cmdArgs, target) if err := execCmd(setting.DefaultVendor, setting.WorkDir, cmdArgs...); err != nil { errors.SetError(fmt.Errorf("fail to run program: %v", err)) return } log.Info("Command executed successfully!") }
// getDepList get list of dependencies in root path format and nature order. func getDepList(ctx *cli.Context, target, pkgPath, vendor string) ([]string, error) { vendorSrc := path.Join(vendor, "src") rootPath := doc.GetRootPath(target) // If work directory is not in GOPATH, then need to setup a vendor path. if !setting.HasGOPATHSetting || !strings.HasPrefix(pkgPath, setting.InstallGopath) { os.RemoveAll(vendorSrc) if !setting.Debug { defer os.RemoveAll(vendor) } // Make link of self. log.Debug("Linking %s...", rootPath) from := pkgPath to := path.Join(vendorSrc, rootPath) if setting.Debug { log.Debug("Linking from %s to %s", from, to) } if err := autoLink(from, to); err != nil { return nil, err } } imports, err := doc.ListImports(target, rootPath, vendor, pkgPath, ctx.Bool("test")) if err != nil { return nil, err } list := make([]string, 0, len(imports)) for _, name := range imports { name = doc.GetRootPath(name) if !base.IsSliceContainsStr(list, name) { list = append(list, name) } } sort.Strings(list) return list, nil }
// downloadPackage downloads package either use version control tools or not. func downloadPackage(ctx *cli.Context, n *doc.Node) (*doc.Node, []string, error) { // fmt.Println(n.VerString()) log.Info("Downloading package: %s", n.VerString()) downloadCache.Set(n.VerString()) vendor := base.GetTempDir() defer os.RemoveAll(vendor) var ( err error imports []string srcPath string ) // Check if only need to use VCS tools. vcs := doc.GetVcsName(n.InstallGopath) // If update, gopath and VCS tools set then use VCS tools to update the package. if ctx.Bool("update") && (ctx.Bool("gopath") || ctx.Bool("local")) && len(vcs) > 0 { if err = n.UpdateByVcs(vcs); err != nil { return nil, nil, fmt.Errorf("fail to update by VCS(%s): %v", n.ImportPath, err) } srcPath = n.InstallGopath } else { if !n.IsGetDepsOnly || !n.IsExist() { // Get revision value from local records. n.Revision = setting.LocalNodes.MustValue(n.RootPath, "value") if err = n.DownloadGopm(ctx); err != nil { errors.AppendError(errors.NewErrDownload(n.ImportPath + ": " + err.Error())) failConut++ os.RemoveAll(n.InstallPath) return nil, nil, nil } } srcPath = n.InstallPath } if n.IsGetDeps { imports, err = getDepList(ctx, n.ImportPath, srcPath, vendor) if err != nil { return nil, nil, fmt.Errorf("fail to list imports(%s): %v", n.ImportPath, err) } if setting.Debug { log.Debug("New imports: %v", imports) } } return n, imports, err }
// setup initializes and checks common environment variables. func setup(ctx *cli.Context) (err error) { setting.Debug = ctx.GlobalBool("debug") log.NonColor = ctx.GlobalBool("noterm") log.Verbose = ctx.Bool("verbose") log.Info("App Version: %s", ctx.App.Version) setting.HomeDir, err = base.HomeDir() if err != nil { return fmt.Errorf("Fail to get home directory: %v", err) } setting.HomeDir = strings.Replace(setting.HomeDir, "\\", "/", -1) setting.InstallRepoPath = path.Join(setting.HomeDir, ".gopm/repos") if runtime.GOOS == "windows" { setting.IsWindows = true } os.MkdirAll(setting.InstallRepoPath, os.ModePerm) log.Info("Local repository path: %s", setting.InstallRepoPath) if !setting.LibraryMode || len(setting.WorkDir) == 0 { setting.WorkDir, err = os.Getwd() if err != nil { return fmt.Errorf("Fail to get work directory: %v", err) } setting.WorkDir = strings.Replace(setting.WorkDir, "\\", "/", -1) } setting.DefaultVendor = path.Join(setting.WorkDir, setting.VENDOR) setting.DefaultVendorSrc = path.Join(setting.DefaultVendor, "src") if !ctx.Bool("remote") { if ctx.Bool("local") { // gf, _, _, err := genGopmfile(ctx) // if err != nil { // return err // } // setting.InstallGopath = gf.MustValue("project", "local_gopath") // if ctx.Command.Name != "gen" { // if com.IsDir(setting.InstallGopath) { // log.Log("Indicated local GOPATH: %s", setting.InstallGopath) // setting.InstallGopath += "/src" // } else { // if setting.LibraryMode { // return fmt.Errorf("Local GOPATH does not exist or is not a directory: %s", // setting.InstallGopath) // } // log.Error("", "Invalid local GOPATH path") // log.Error("", "Local GOPATH does not exist or is not a directory:") // log.Error("", "\t"+setting.InstallGopath) // log.Help("Try 'go help gopath' to get more information") // } // } } else { // Get GOPATH. setting.InstallGopath = base.GetGOPATHs()[0] if base.IsDir(setting.InstallGopath) { log.Info("Indicated GOPATH: %s", setting.InstallGopath) setting.InstallGopath += "/src" setting.HasGOPATHSetting = true } else { if ctx.Bool("gopath") { return fmt.Errorf("Local GOPATH does not exist or is not a directory: %s", setting.InstallGopath) } else { // It's OK that no GOPATH setting // when user does not specify to use. log.Warn("No GOPATH setting available") } } } } setting.ConfigFile = path.Join(setting.HomeDir, ".gopm/data/gopm.ini") if err = setting.LoadConfig(); err != nil { return err } setting.PkgNameListFile = path.Join(setting.HomeDir, ".gopm/data/pkgname.list") if err = setting.LoadPkgNameList(); err != nil { return err } setting.LocalNodesFile = path.Join(setting.HomeDir, ".gopm/data/localnodes.list") if err = setting.LoadLocalNodes(); err != nil { return err } return nil }
func runBin(ctx *cli.Context) { if err := setup(ctx); err != nil { errors.SetError(err) return } if len(ctx.Args()) != 1 { errors.SetError(fmt.Errorf("Incorrect number of arguments for command: should have 1")) return } // Check if given directory exists if specified. if ctx.IsSet("dir") && !base.IsDir(ctx.String("dir")) { errors.SetError(fmt.Errorf("Indicated path does not exist or not a directory")) return } // Parse package version. info := ctx.Args().First() pkgPath := info n := doc.NewNode(pkgPath, doc.BRANCH, "", true) if i := strings.Index(info, "@"); i > -1 { pkgPath = info[:i] var err error tp, val, err := validPkgInfo(info[i+1:]) if err != nil { errors.SetError(err) return } n = doc.NewNode(pkgPath, tp, val, !ctx.Bool("download")) } // Check package name. if !strings.Contains(pkgPath, "/") { tmpPath, err := setting.GetPkgFullPath(pkgPath) if err != nil { errors.SetError(err) return } if tmpPath != pkgPath { n = doc.NewNode(tmpPath, n.Type, n.Value, n.IsGetDeps) } } if err := downloadPackages(".", ctx, []*doc.Node{n}); err != nil { errors.SetError(err) return } // Check if previous steps were successful. if !n.IsExist() { errors.SetError(fmt.Errorf("Download steps weren't successful")) return } tmpVendor := path.Join("vendor", path.Base(n.RootPath)) os.RemoveAll(tmpVendor) os.RemoveAll(setting.VENDOR) // TODO: should use .gopm/temp path. if err := autoLink(n.InstallPath, tmpVendor); err != nil { errors.SetError(fmt.Errorf("Fail to link slef: %v", err)) return } os.Chdir(tmpVendor) oldWorkDir := setting.WorkDir setting.WorkDir = path.Join(setting.WorkDir, tmpVendor) if !setting.Debug { defer func() { os.Chdir(oldWorkDir) os.RemoveAll("vendor") os.RemoveAll(setting.VENDOR) }() } // if err := buildBinary(ctx); err != nil { // errors.SetError(err) // return // } if err := linkVendors(ctx, n.ImportPath); err != nil { errors.SetError(err) return } log.Info("Installing...") cmdArgs := []string{"go", "install"} if ctx.Bool("verbose") { cmdArgs = append(cmdArgs, "-v") } cmdArgs = append(cmdArgs, n.ImportPath) if err := execCmd(setting.DefaultVendor, setting.WorkDir, cmdArgs...); err != nil { errors.SetError(fmt.Errorf("fail to run program: %v", err)) return } gf, _, err := parseGopmfile(setting.GOPMFILE) if err != nil { errors.SetError(err) return } // Because build command moved binary to root path. binName := path.Base(n.RootPath) binPath := path.Join(setting.DefaultVendor, "bin", path.Base(n.RootPath)) if runtime.GOOS == "windows" { binName += ".exe" } // Move binary to given directory. movePath := oldWorkDir if ctx.IsSet("dir") { movePath = ctx.String("dir") } else if strings.HasPrefix(n.ImportPath, "code.google.com/p/go.tools/cmd/") { movePath = path.Join(runtime.GOROOT(), "pkg/tool", runtime.GOOS+"_"+runtime.GOARCH) log.Info("Command executed successfully!") fmt.Println("Binary has been built into: " + movePath) return } if !base.IsFile(binPath) { errors.SetError(fmt.Errorf("Previous steps weren't successful or the project does not contain main package")) return } if base.IsExist(path.Join(movePath, binName)) { if err := os.Remove(path.Join(movePath, binName)); err != nil { log.Warn("Cannot remove binary in work directory: %v", err) } } if err := os.Rename(binPath, movePath+"/"+binName); err != nil { errors.SetError(fmt.Errorf("Fail to move binary: %v", err)) return } os.Chmod(movePath+"/"+binName, os.ModePerm) includes := strings.Split(gf.MustValue("res", "include"), "|") if len(includes) > 0 { log.Info("Copying resources to %s", movePath) for _, include := range includes { if base.IsDir(include) { os.RemoveAll(path.Join(movePath, include)) if err := base.CopyDir(include, filepath.Join(movePath, include)); err != nil { errors.AppendError(errors.NewErrCopyResource(include)) } } } } log.Info("Command executed successfully!") fmt.Println("Binary has been built into: " + movePath) }
func runGet(ctx *cli.Context) { if err := setup(ctx); err != nil { errors.SetError(err) return } // Check option conflicts. hasConflict := false names := "" switch { case ctx.Bool("local") && ctx.Bool("gopath"): hasConflict = true names = "'--local, -l' and '--gopath, -g'" case ctx.Bool("local") && ctx.Bool("remote"): hasConflict = true names = "'--local, -l' and '--remote, -r'" case ctx.Bool("gopath") && ctx.Bool("remote"): hasConflict = true names = "'--gopath, -g' and '--remote, -r'" } if hasConflict { errors.SetError(fmt.Errorf("Command options have conflicts: %s", names)) return } var err error // Check number of arguments to decide which function to call. if len(ctx.Args()) == 0 { if ctx.Bool("download") { errors.SetError(fmt.Errorf("Not enough arguments for option: '--download, -d'")) return } err = getByGopmfile(ctx) } else { err = getByPaths(ctx) } if err != nil { errors.SetError(err) } }
// 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(target string, ctx *cli.Context, nodes []*doc.Node) (err error) { for _, n := range nodes { // Check if it is a valid remote path or C. if n.ImportPath == "C" { continue } else if !base.IsValidRemotePath(n.ImportPath) { // Invalid import path. if setting.LibraryMode { errors.AppendError(errors.NewErrInvalidPackage(n.VerString())) } log.Error("Skipped invalid package: " + n.VerString()) failConut++ continue } // Valid import path. if isSubpackage(n.RootPath, target) { continue } // Indicates whether need to download package or update. if n.IsFixed() && n.IsExist() { n.IsGetDepsOnly = true } if downloadCache.Get(n.VerString()) { if !skipCache.Get(n.VerString()) { skipCache.Set(n.VerString()) log.Debug("Skipped downloaded package: %s", n.VerString()) } continue } if !ctx.Bool("update") { // Check if package has been downloaded. if n.IsExist() { if !skipCache.Get(n.VerString()) { skipCache.Set(n.VerString()) log.Info("%s", n.InstallPath) log.Debug("Skipped installed package: %s", n.VerString()) } // Only copy when no version control. if !copyCache.Get(n.VerString()) && (ctx.Bool("gopath") || ctx.Bool("local")) { copyCache.Set(n.VerString()) if err = n.CopyToGopath(); err != nil { return err } } continue } else { setting.LocalNodes.SetValue(n.RootPath, "value", "") } } // Download package. nod, imports, err := downloadPackage(ctx, n) if err != nil { return err } for _, name := range imports { var gf *goconfig.ConfigFile gfPath := path.Join(n.InstallPath, setting.GOPMFILE) // Check if has gopmfile. if base.IsFile(gfPath) { log.Info("Found gopmfile: %s", n.VerString()) var err error gf, _, err = parseGopmfile(gfPath) if err != nil { return fmt.Errorf("fail to parse gopmfile(%s): %v", gfPath, err) } } // Need to download dependencies. // Generate temporary nodes. nodes := make([]*doc.Node, len(imports)) for i := range nodes { nodes[i] = doc.NewNode(name, doc.BRANCH, "", !ctx.Bool("download")) if gf == nil { continue } // Check if user specified the version. if v := gf.MustValue("deps", imports[i]); len(v) > 0 { nodes[i].Type, nodes[i].Value, err = validPkgInfo(v) if err != nil { return err } } } if err = downloadPackages(target, ctx, nodes); err != nil { return err } } // Only save package information with specific commit. if nod == nil { continue } // Save record in local nodes. log.Info("Got %s", n.VerString()) downloadCount++ // Only save non-commit node. if nod.IsEmptyVal() && len(nod.Revision) > 0 { setting.LocalNodes.SetValue(nod.RootPath, "value", nod.Revision) } // If update set downloadPackage will use VSC tools to download the package, // else just download to local repository and copy to GOPATH. if !nod.HasVcs() && !copyCache.Get(n.RootPath) && (ctx.Bool("gopath") || ctx.Bool("local")) { copyCache.Set(n.RootPath) if err = nod.CopyToGopath(); err != nil { return err } } } return nil }
func runUpdate(ctx *cli.Context) { if setting.LibraryMode { errors.SetError(fmt.Errorf("Library mode does not support update command")) return } if err := setup(ctx); err != nil { errors.SetError(err) return } isAnythingUpdated := false localVerInfo := loadLocalVerInfo() // Get remote version info. var remoteVerInfo version if err := base.HttpGetJSON(doc.HttpClient, "http://gopm.io/VERSION.json", &remoteVerInfo); err != nil { log.Fatal("Fail to fetch VERSION.json: %v", err) } // Package name list. if remoteVerInfo.PackageNameList > localVerInfo.PackageNameList { log.Info("Updating pkgname.list...%v > %v", localVerInfo.PackageNameList, remoteVerInfo.PackageNameList) data, err := base.HttpGetBytes(doc.HttpClient, "https://raw.githubusercontent.com/gpmgo/docs/master/pkgname.list", nil) if err != nil { log.Warn("Fail to update pkgname.list: %v", err) } else { if err = ioutil.WriteFile(setting.PkgNameListFile, data, os.ModePerm); err != nil { log.Fatal("Fail to save pkgname.list: %v", err) } log.Info("Update pkgname.list to %v succeed!", remoteVerInfo.PackageNameList) isAnythingUpdated = true } } // Gopm. if remoteVerInfo.Gopm > setting.VERSION { log.Info("Updating gopm...%v > %v", setting.VERSION, remoteVerInfo.Gopm) tmpDir := base.GetTempDir() tmpBinPath := path.Join(tmpDir, "gopm") if runtime.GOOS == "windows" { tmpBinPath += ".exe" } os.MkdirAll(path.Dir(tmpBinPath), os.ModePerm) os.Remove(tmpBinPath) // Fetch code. args := []string{"bin", "-u", "-r", "-d=" + tmpDir} if ctx.Bool("verbose") { args = append(args, "-v") } args = append(args, "github.com/gpmgo/gopm") stdout, stderr, err := base.ExecCmd("gopm", args...) if err != nil { log.Fatal("Fail to execute 'bin -u -r -d=/Users/jiahuachen/.gopm/temp -v github.com/gpmgo/gopm: %s", stderr) } if len(stdout) > 0 { fmt.Print(stdout) } // Check if previous steps were successful. if !base.IsExist(tmpBinPath) { log.Error("Fail to continue command") log.Fatal("Previous steps weren't successful, no binary produced") } movePath, err := execPath() if err != nil { log.Fatal("Fail to get execute path: %v", err) } log.Info("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.Fatal("Fail to move binary: %v", err) } os.Chmod(movePath+"/"+path.Base(tmpBinPath), os.ModePerm) } else { batPath := path.Join(tmpDir, "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.Close() attr := &os.ProcAttr{ Dir: setting.WorkDir, Env: os.Environ(), Files: []*os.File{os.Stdin, os.Stdout, os.Stderr}, } if _, err = os.StartProcess(batPath, []string{batPath}, attr); err != nil { log.Error("Update", "Fail to start bat process") log.Fatal("", err.Error()) } } log.Info("Command execute successfully!") isAnythingUpdated = true } if isAnythingUpdated { // Save JSON. verPath := path.Join(setting.HomeDir, setting.VERINFO) os.MkdirAll(path.Dir(verPath), os.ModePerm) f, err := os.Create(verPath) if err != nil { log.Fatal("Fail to create VERSION.json: %v", err) } if err := json.NewEncoder(f).Encode(&remoteVerInfo); err != nil { log.Fatal("Fail to encode VERSION.json: %v", err) } } else { log.Info("Nothing need to be updated") } log.Info("Exit old gopm") }
func runGet(ctx *cli.Context) { if err := setup(ctx); err != nil { errors.SetError(err) return } // Check option conflicts. hasConflict := false names := "" switch { case ctx.Bool("local") && ctx.Bool("gopath"): hasConflict = true names = "'--local, -l' and '--gopath, -g'" case ctx.Bool("local") && ctx.Bool("remote"): hasConflict = true names = "'--local, -l' and '--remote, -r'" case ctx.Bool("gopath") && ctx.Bool("remote"): hasConflict = true names = "'--gopath, -g' and '--remote, -r'" } if hasConflict { errors.SetError(fmt.Errorf("Command options have conflicts: %s", names)) return } var err error // Check number of arguments to decide which function to call. if len(ctx.Args()) == 0 { if ctx.Bool("download") { errors.SetError(fmt.Errorf("Not enough arguments for option: '--download, -d'")) return } err = getByGopmfile(ctx) } else { err = getByPaths(ctx) } if err != nil { errors.SetError(err) return } if len(ctx.Args()) > 0 && ctx.Bool("save") { gf, _, err := parseGopmfile(setting.GOPMFILE) if err != nil { errors.SetError(err) return } for _, info := range ctx.Args() { if i := strings.Index(info, "@"); i > -1 { gf.SetValue("deps", info[:i], info[i+1:]) } else { gf.SetValue("deps", info, "") } } setting.SaveGopmfile(gf, setting.GOPMFILE) } }
func runGen(ctx *cli.Context) { if err := setup(ctx); err != nil { errors.SetError(err) return } gfPath := path.Join(setting.WorkDir, setting.GOPMFILE) if !setting.HasGOPATHSetting && !base.IsFile(gfPath) { log.Warn("Dependency list may contain package itself without GOPATH setting and gopmfile.") } gf, target, err := parseGopmfile(gfPath) if err != nil { errors.SetError(err) return } list, err := getDepList(ctx, target, setting.WorkDir, setting.DefaultVendor) if err != nil { errors.SetError(err) return } for _, name := range list { // Check if user has specified the version. if val := gf.MustValue("deps", name); len(val) == 0 { gf.SetValue("deps", name, "") } } // Check resources. if _, err = gf.GetValue("res", "include"); err != nil { resList := make([]string, 0, len(setting.CommonRes)) for _, res := range setting.CommonRes { if base.IsExist(res) { resList = append(resList, res) } } gf.SetValue("res", "include", strings.Join(resList, "|")) } if err = setting.SaveGopmfile(gf, gfPath); err != nil { errors.SetError(err) return } if ctx.Bool("local") { localGopath := gf.MustValue("project", "local_gopath") if len(localGopath) == 0 { localGopath = "./vendor" gf.SetValue("project", "local_gopath", localGopath) if err = setting.SaveGopmfile(gf, gfPath); err != nil { errors.SetError(err) return } } for _, name := range []string{"src", "pkg", "bin"} { os.MkdirAll(path.Join(localGopath, name), os.ModePerm) } } log.Info("Generate gopmfile successfully!") }
func linkVendors(ctx *cli.Context, optTarget string) error { gfPath := path.Join(setting.WorkDir, setting.GOPMFILE) gf, target, err := parseGopmfile(gfPath) if err != nil { return fmt.Errorf("fail to parse gopmfile: %v", err) } if len(optTarget) > 0 { target = optTarget } rootPath := doc.GetRootPath(target) // TODO: local support. // Make link of self. log.Debug("Linking %s...", rootPath) from := setting.WorkDir to := path.Join(setting.DefaultVendorSrc, rootPath) if setting.Debug { log.Debug("Linking from %s to %s", from, to) } if err := autoLink(from, to); err != nil { return fmt.Errorf("fail to link self: %v", err) } // Check and loads dependency packages. log.Debug("Loading dependencies...") imports, err := doc.ListImports(target, rootPath, setting.DefaultVendor, setting.WorkDir, ctx.String("tags"), ctx.Bool("test")) if err != nil { return fmt.Errorf("fail to list imports: %v", err) } stack := make([]*doc.Pkg, len(imports)) for i, name := range imports { name := doc.GetRootPath(name) tp, val, err := validPkgInfo(gf.MustValue("deps", name)) if err != nil { return fmt.Errorf("fail to validate package(%s): %v", name, err) } stack[i] = doc.NewPkg(name, tp, val) } // FIXME: at least link once, need a set lastIdx := len(stack) - 1 for lastIdx >= 0 { pkg := stack[lastIdx] linkPath := path.Join(setting.DefaultVendorSrc, pkg.RootPath) if setting.Debug { log.Debug("Import path: %s", pkg.ImportPath) log.Debug("Linking path: %s", linkPath) } if base.IsExist(linkPath) { stack = stack[:lastIdx] lastIdx = len(stack) - 1 continue } if pkg.IsEmptyVal() && setting.HasGOPATHSetting && base.IsExist(path.Join(setting.InstallGopath, pkg.RootPath)) { stack = stack[:lastIdx] lastIdx = len(stack) - 1 continue } venderPath := path.Join(setting.InstallRepoPath, pkg.RootPath+pkg.ValSuffix()) if !base.IsExist(venderPath) { return fmt.Errorf("package not installed: %s", pkg.RootPath+pkg.VerSuffix()) } log.Debug("Linking %s...", pkg.RootPath+pkg.ValSuffix()) if err := autoLink(venderPath, linkPath); err != nil { return fmt.Errorf("fail to link dependency(%s): %v", pkg.RootPath, err) } stack = stack[:lastIdx] gf, target, err := parseGopmfile(path.Join(linkPath, setting.GOPMFILE)) if err != nil { return fmt.Errorf("fail to parse gopmfile(%s): %v", linkPath, err) } // parseGopmfile only returns right target when parse work directory. target = pkg.RootPath rootPath := target imports, err := doc.ListImports(target, rootPath, setting.DefaultVendor, linkPath, ctx.String("tags"), ctx.Bool("test")) if err != nil { errors.SetError(err) } for _, name := range imports { if name == "C" { continue } name := doc.GetRootPath(name) tp, val, err := validPkgInfo(gf.MustValue("deps", name)) if err != nil { return fmt.Errorf("fail to validate package(%s): %v", name, err) } stack = append(stack, doc.NewPkg(name, tp, val)) } lastIdx = len(stack) - 1 } return nil }