// getDepList gets 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) { // 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.String("tags"), 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 }
// ListImports checks and returns a list of imports of given import path and options. func ListImports(importPath, rootPath, vendorPath, srcPath, tags string, isTest bool) ([]string, error) { oldGOPATH := os.Getenv("GOPATH") sep := ":" if runtime.GOOS == "windows" { sep = ";" } ctxt := build.Default ctxt.BuildTags = strings.Split(tags, " ") ctxt.GOPATH = vendorPath + sep + oldGOPATH if setting.Debug { log.Debug("Import/root path: %s : %s", importPath, rootPath) log.Debug("Context GOPATH: %s", ctxt.GOPATH) log.Debug("Source path: %s", srcPath) } pkg, err := ctxt.Import(importPath, srcPath, build.AllowBinary) if err != nil { if _, ok := err.(*build.NoGoError); !ok { return nil, fmt.Errorf("fail to get imports(%s): %v", importPath, err) } log.Warn("Getting imports: %v", err) } rawImports := pkg.Imports numImports := len(rawImports) if isTest { rawImports = append(rawImports, pkg.TestImports...) numImports = len(rawImports) } imports := make([]string, 0, numImports) for _, name := range rawImports { if IsGoRepoPath(name) { continue } else if strings.HasPrefix(name, rootPath) { moreImports, err := ListImports(name, rootPath, vendorPath, srcPath, tags, isTest) if err != nil { return nil, err } imports = append(imports, moreImports...) continue } if setting.Debug { log.Debug("Found dependency: %s", name) } imports = append(imports, name) } return imports, nil }
// DownloadGopm downloads remote package from gopm registry. func (n *Node) DownloadGopm(ctx *cli.Context) error { resp, err := http.Get(fmt.Sprintf("%s%s?pkgname=%s&revision=%s", setting.RegistryUrl, setting.URL_API_DOWNLOAD, n.RootPath, n.Value)) if err != nil { return fmt.Errorf("fail to make request: %v", err) } if resp.StatusCode != 200 { var apiErr ApiError if err = json.NewDecoder(resp.Body).Decode(&apiErr); err != nil { return fmt.Errorf("fail to decode response JSON: %v", err) } return errors.New(apiErr.Error) } tmpPath := path.Join(setting.HomeDir, ".gopm/temp/archive", n.RootPath+"-"+base.ToStr(time.Now().Nanosecond())+".zip") defer os.Remove(tmpPath) if setting.Debug { log.Debug("Temp archive path: %s", tmpPath) } os.MkdirAll(path.Dir(tmpPath), os.ModePerm) fw, err := os.Create(tmpPath) if err != nil { return err } if _, err = io.Copy(fw, resp.Body); err != nil { return fmt.Errorf("fail to save archive: %v", err) } fw.Close() // Remove old files. os.RemoveAll(n.InstallPath) os.MkdirAll(path.Dir(n.InstallPath), os.ModePerm) var rootDir string var extractFn = func(fullName string, fi os.FileInfo) error { if len(rootDir) == 0 { rootDir = strings.Split(fullName, "/")[0] } return nil } if err := zip.ExtractToFunc(tmpPath, path.Dir(n.InstallPath), extractFn); err != nil { return fmt.Errorf("fail to extract archive: %v", err) } else if err = os.Rename(path.Join(path.Dir(n.InstallPath), rootDir), n.InstallPath); err != nil { return fmt.Errorf("fail to rename directory: %v", err) } // fmt.Println(rootDir) return nil }
func buildBinary(ctx *cli.Context, args ...string) error { _, target, err := parseGopmfile(setting.GOPMFILE) if err != nil { return err } if err := linkVendors(ctx, ""); err != nil { return err } log.Info("Building...") cmdArgs := append([]string{"go", "build"}, args...) // Set output binary name cmdArgs = append(cmdArgs, "-o") if ctx.IsSet("o") { cmdArgs = append(cmdArgs, ctx.String("o")) } else { cmdArgs = append(cmdArgs, path.Base(target)) } if len(ctx.String("tags")) > 0 { cmdArgs = append(cmdArgs, "-tags") cmdArgs = append(cmdArgs, ctx.String("tags")) } log.Debug("Args: %v", cmdArgs) if err := execCmd(setting.DefaultVendor, setting.WorkDir, cmdArgs...); err != nil { return fmt.Errorf("fail to build program: %v", err) } if setting.IsWindowsXP { fName := path.Base(target) binName := fName + ".exe" os.Remove(binName) exePath := path.Join(setting.DefaultVendorSrc, target, binName) if base.IsFile(exePath) { if err := os.Rename(exePath, path.Join(setting.WorkDir, binName)); err != nil { return fmt.Errorf("fail to move binary: %v", err) } } else { log.Warn("No binary generated") } } return 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 }
// 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 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 }