func (i *Installer) List(conf *cfg.Config) []*cfg.Dependency { base := "." vpath := i.VendorPath() ic := newImportCache() v := &VersionHandler{ Destination: vpath, Use: ic, Imported: make(map[string]bool), Conflicts: make(map[string]bool), Config: conf, } // Update imports res, err := dependency.NewResolver(base) if err != nil { msg.Die("Failed to create a resolver: %s", err) } res.Config = conf res.VersionHandler = v msg.Info("Resolving imports") _, err = allPackages(conf.Imports, res) if err != nil { msg.Die("Failed to retrieve a list of dependencies: %s", err) } msg.Warn("devImports not resolved.") return conf.Imports }
// Get fetches one or more dependencies and installs. // // This includes resolving dependency resolution and re-generating the lock file. func Get(names []string, installer *repo.Installer, insecure, skipRecursive bool) { base := gpath.Basepath() EnsureGopath() EnsureVendorDir() conf := EnsureConfig() glidefile, err := gpath.Glide() if err != nil { msg.Die("Could not find Glide file: %s", err) } // Add the packages to the config. if err := addPkgsToConfig(conf, names, insecure); err != nil { msg.Die("Failed to get new packages: %s", err) } // Fetch the new packages. Can't resolve versions via installer.Update if // get is called while the vendor/ directory is empty so we checkout // everything. installer.Checkout(conf, false) // Prior to resolving dependencies we need to start working with a clone // of the conf because we'll be making real changes to it. confcopy := conf.Clone() if !skipRecursive { // Get all repos and update them. // TODO: Can we streamline this in any way? The reason that we update all // of the dependencies is that we need to re-negotiate versions. For example, // if an existing dependency has the constraint >1.0 and this new package // adds the constraint <2.0, then this may re-resolve the existing dependency // to be between 1.0 and 2.0. But changing that dependency may then result // in that dependency's dependencies changing... so we sorta do the whole // thing to be safe. err = installer.Update(confcopy) if err != nil { msg.Die("Could not update packages: %s", err) } } // Set Reference if err := repo.SetReference(confcopy); err != nil { msg.Error("Failed to set references: %s", err) } // VendoredCleanup if installer.UpdateVendored { repo.VendoredCleanup(confcopy) } // Write YAML if err := conf.WriteFile(glidefile); err != nil { msg.Die("Failed to write glide YAML file: %s", err) } if !skipRecursive { // Write lock writeLock(conf, confcopy, base) } else { msg.Warn("Skipping lockfile generation because full dependency tree is not being calculated") } }
// List lists all of the dependencies of the current project. // // Params: // - dir (string): basedir // - deep (bool): whether to do a deep scan or a shallow scan // - format (string): The format to output (text, json, json-pretty) func List(basedir string, deep bool, format string) { basedir, err := filepath.Abs(basedir) if err != nil { msg.Die("Could not read directory: %s", err) } r, err := dependency.NewResolver(basedir) if err != nil { msg.Die("Could not create a resolver: %s", err) } h := &dependency.DefaultMissingPackageHandler{Missing: []string{}, Gopath: []string{}, Prefix: "vendor"} r.Handler = h localPkgs, _, err := r.ResolveLocal(deep) if err != nil { msg.Die("Error listing dependencies: %s", err) } sort.Strings(localPkgs) installed := make([]string, len(localPkgs)) for i, pkg := range localPkgs { relPkg, err := filepath.Rel(basedir, pkg) if err != nil { // msg.Warn("Failed to Rel path: %s", err) relPkg = pkg } installed[i] = relPkg } l := PackageList{ Installed: installed, Missing: h.Missing, Gopath: h.Gopath, } outputList(l, format) }
func outputList(l PackageList, format string) { switch format { case textFormat: msg.Puts("INSTALLED packages:") for _, pkg := range l.Installed { msg.Puts("\t%s", pkg) } if len(l.Missing) > 0 { msg.Puts("\nMISSING packages:") for _, pkg := range l.Missing { msg.Puts("\t%s", pkg) } } if len(l.Gopath) > 0 { msg.Puts("\nGOPATH packages:") for _, pkg := range l.Gopath { msg.Puts("\t%s", pkg) } } case jsonFormat: json.NewEncoder(msg.Default.Stdout).Encode(l) case jsonPrettyFormat: b, err := json.MarshalIndent(l, "", " ") if err != nil { msg.Die("could not unmarshal package list: %s", err) } msg.Puts(string(b)) default: msg.Die("invalid output format: must be one of: json|json-pretty|text") } }
// Install installs a vendor directory based on an existing Glide configuration. func Install(installer *repo.Installer, stripVendor bool) { cache.SystemLock() base := "." // Ensure GOPATH EnsureGopath() EnsureVendorDir() conf := EnsureConfig() // Lockfile exists if !gpath.HasLock(base) { msg.Info("Lock file (glide.lock) does not exist. Performing update.") Update(installer, false, stripVendor) return } // Load lockfile lock, err := cfg.ReadLockFile(filepath.Join(base, gpath.LockFile)) if err != nil { msg.Die("Could not load lockfile.") } // Verify lockfile hasn't changed hash, err := conf.Hash() if err != nil { msg.Die("Could not load lockfile.") } else if hash != lock.Hash { fmt.Println(hash, lock.Hash) foo, _ := conf.Marshal() fmt.Println(string(foo)) msg.Warn("Lock file may be out of date. Hash check of YAML failed. You may need to run 'update'") } // Install newConf, err := installer.Install(lock, conf) if err != nil { msg.Die("Failed to install: %s", err) } msg.Info("Setting references.") // Set reference if err := repo.SetReference(newConf, installer.ResolveTest); err != nil { msg.Die("Failed to set references: %s (Skip to cleanup)", err) } err = installer.Export(newConf) if err != nil { msg.Die("Unable to export dependencies to vendor directory: %s", err) } if stripVendor { msg.Info("Removing nested vendor and Godeps/_workspace directories...") err := gpath.StripVendor() if err != nil { msg.Err("Unable to strip vendor directories: %s", err) } } }
func writeLock(conf, confcopy *cfg.Config, base string) { hash, err := conf.Hash() if err != nil { msg.Die("Failed to generate config hash. Unable to generate lock file.") } lock := cfg.NewLockfile(confcopy.Imports, hash) if err := lock.WriteFile(filepath.Join(base, gpath.LockFile)); err != nil { msg.Die("Failed to write glide lock file: %s", err) } }
// EnsureVendorDir ensures that a vendor/ directory is present in the cwd. func EnsureVendorDir() { fi, err := os.Stat(gpath.VendorDir) if err != nil { msg.Debug("Creating %s", gpath.VendorDir) if err := os.MkdirAll(gpath.VendorDir, os.ModeDir|0755); err != nil { msg.Die("Could not create %s: %s", gpath.VendorDir, err) } } else if !fi.IsDir() { msg.Die("Vendor is not a directory") } }
// writeConfigToFileOrStdout is a convenience function for import utils. func writeConfigToFileOrStdout(config *cfg.Config, dest string) { if dest != "" { if err := config.WriteFile(dest); err != nil { msg.Die("Failed to write %s: %s", gpath.GlideFile, err) } } else { o, err := config.Marshal() if err != nil { msg.Die("Error encoding config: %s", err) } msg.Default.Stdout.Write(o) } }
// ImportGB imports GB dependencies into the present glide config. func ImportGB(dest string) { base := "." config := EnsureConfig() if !gb.Has(base) { msg.Die("There is no GB manifest to import.") } deps, err := gb.Parse(base) if err != nil { msg.Die("Failed to extract GB manifest: %s", err) } appendImports(deps, config) writeConfigToFileOrStdout(config, dest) }
// ImportGom imports a Gomfile. func ImportGom(dest string) { base := "." config := EnsureConfig() if !gom.Has(base) { msg.Die("No gom data found.") } deps, err := gom.Parse(base) if err != nil { msg.Die("Failed to extract Gomfile: %s", err) } appendImports(deps, config) writeConfigToFileOrStdout(config, dest) }
// EnsureGopath fails if GOPATH is not set, or if $GOPATH/src is missing. // // Otherwise it returns the value of GOPATH. func EnsureGopath() string { gp := os.Getenv("GOPATH") if gp == "" { msg.Die("$GOPATH is not set.") } _, err := os.Stat(path.Join(gp, "src")) if err != nil { msg.Error("Could not find %s/src.\n", gp) msg.Info("As of Glide 0.5/Go 1.5, this is required.\n") msg.Die("Wihtout src, cannot continue. %s", err) } return gp }
// Update updates all dependencies. // // It begins with the dependencies in the config file, but also resolves // transitive dependencies. The returned lockfile has all of the dependencies // listed, but the version reconciliation has not been done. // // In other words, all versions in the Lockfile will be empty. func (i *Installer) Update(conf *cfg.Config) error { base := "." vpath := i.VendorPath() ic := newImportCache() m := &MissingPackageHandler{ destination: vpath, cache: i.UseCache, cacheGopath: i.UseCacheGopath, useGopath: i.UseGopath, home: i.Home, force: i.Force, updateVendored: i.UpdateVendored, Config: conf, Use: ic, updated: i.Updated, } v := &VersionHandler{ Destination: vpath, Use: ic, Imported: make(map[string]bool), Conflicts: make(map[string]bool), Config: conf, } // Update imports res, err := dependency.NewResolver(base) if err != nil { msg.Die("Failed to create a resolver: %s", err) } res.Config = conf res.Handler = m res.VersionHandler = v res.ResolveAllFiles = i.ResolveAllFiles msg.Info("Resolving imports") _, err = allPackages(conf.Imports, res) if err != nil { msg.Die("Failed to retrieve a list of dependencies: %s", err) } if len(conf.DevImports) > 0 { msg.Warn("dev imports not resolved.") } err = ConcurrentUpdate(conf.Imports, vpath, i, conf) return err }
func (d *VersionHandler) pkgPath(pkg string) string { root, sub := util.NormalizeName(pkg) // For the parent applications source skip the cache. if root == d.Config.Name { pth := gpath.Basepath() return filepath.Join(pth, filepath.FromSlash(sub)) } dep := d.Config.Imports.Get(root) if dep == nil { dep = d.Config.DevImports.Get(root) } if dep == nil { dep, _ = d.Use.Get(root) if dep == nil { dep = &cfg.Dependency{Name: root} } } key, err := cache.Key(dep.Remote()) if err != nil { msg.Die("Error generating cache key for %s", dep.Name) } return filepath.Join(cache.Location(), "src", key, filepath.FromSlash(sub)) }
func guessImportDeps(base string, config *cfg.Config) { msg.Info("Attempting to import from other package managers (use --skip-import to skip)") deps := []*cfg.Dependency{} absBase, err := filepath.Abs(base) if err != nil { msg.Die("Failed to resolve location of %s: %s", base, err) } if d, ok := guessImportGodep(absBase); ok { msg.Info("Importing Godep configuration") msg.Warn("Godep uses commit id versions. Consider using Semantic Versions with Glide") deps = d } else if d, ok := guessImportGPM(absBase); ok { msg.Info("Importing GPM configuration") deps = d } else if d, ok := guessImportGB(absBase); ok { msg.Info("Importing GB configuration") deps = d } for _, i := range deps { if i.Reference == "" { msg.Info("--> Found imported reference to %s", i.Name) } else { msg.Info("--> Found imported reference to %s at revision %s", i.Name, i.Reference) } config.Imports = append(config.Imports, i) } }
// MirrorsList displays a list of currently setup mirrors. func MirrorsList() error { home := gpath.Home() op := filepath.Join(home, "mirrors.yaml") if _, err := os.Stat(op); os.IsNotExist(err) { msg.Info("No mirrors exist. No mirrors.yaml file not found") return nil } ov, err := mirrors.ReadMirrorsFile(op) if err != nil { msg.Die("Unable to read mirrors.yaml file: %s", err) } if len(ov.Repos) == 0 { msg.Info("No mirrors found") return nil } msg.Info("Mirrors...") for _, r := range ov.Repos { if r.Vcs == "" { msg.Info("--> %s replaced by %s", r.Original, r.Repo) } else { msg.Info("--> %s replaced by %s (%s)", r.Original, r.Repo, r.Vcs) } } return nil }
// Create creates/initializes a new Glide repository. // // This will fail if a glide.yaml already exists. // // By default, this will scan the present source code directory for dependencies. // // If skipImport is set to true, this will not attempt to import from an existing // GPM, Godep, or GB project if one should exist. However, it will still attempt // to read the local source to determine required packages. func Create(base string, skipImport, nonInteractive bool) { glidefile := gpath.GlideFile // Guard against overwrites. guardYAML(glidefile) // Guess deps conf := guessDeps(base, skipImport) // Write YAML msg.Info("Writing configuration file (%s)", glidefile) if err := conf.WriteFile(glidefile); err != nil { msg.Die("Could not save %s: %s", glidefile, err) } var res bool if !nonInteractive { msg.Info("Would you like Glide to help you find ways to improve your glide.yaml configuration?") msg.Info("If you want to revisit this step you can use the config-wizard command at any time.") msg.Info("Yes (Y) or No (N)?") res = msg.PromptUntilYorN() if res { ConfigWizard(base) } } if !res { msg.Info("You can now edit the glide.yaml file. Consider:") msg.Info("--> Using versions and ranges. See https://glide.sh/docs/versions/") msg.Info("--> Adding additional metadata. See https://glide.sh/docs/glide.yaml/") msg.Info("--> Running the config-wizard command to improve the versions in your configuration") } }
// Info prints information about a project based on a passed in format. func Info(format string) { conf := EnsureConfig() var buffer bytes.Buffer varInit := false for _, varfmt := range format { if varInit { switch varfmt { case 'n': buffer.WriteString(conf.Name) case 'd': buffer.WriteString(conf.Description) case 'h': buffer.WriteString(conf.Home) case 'l': buffer.WriteString(conf.License) default: msg.Die("Invalid format %s", string(varfmt)) } } else { switch varfmt { case '%': varInit = true continue default: buffer.WriteString(string(varfmt)) } } varInit = false } msg.Puts(buffer.String()) }
// Plugin attempts to find and execute a plugin based on a command. // // Exit code 99 means the plugin was never executed. Code 1 means the program // exited badly. func Plugin(command string, args []string) { cwd, err := os.Getwd() if err != nil { msg.ExitCode(99) msg.Die("Could not get working directory: %s", err) } cmd := "glide-" + command var fullcmd string if fullcmd, err = exec.LookPath(cmd); err != nil { fullcmd = cwd + "/" + cmd if _, err := os.Stat(fullcmd); err != nil { msg.ExitCode(99) msg.Die("Command %s does not exist.", cmd) } } // Turning os.Args first argument from `glide` to `glide-command` args[0] = cmd // Removing the first argument (command) removed := false for i, v := range args { if removed == false && v == command { args = append(args[:i], args[i+1:]...) removed = true } } pa := os.ProcAttr{ Files: []*os.File{os.Stdin, os.Stdout, os.Stderr}, Dir: cwd, } msg.Debug("Delegating to plugin %s (%v)\n", fullcmd, args) proc, err := os.StartProcess(fullcmd, args, &pa) if err != nil { msg.Err("Failed to execute %s: %s", cmd, err) os.Exit(98) } if _, err := proc.Wait(); err != nil { msg.Err(err.Error()) os.Exit(1) } }
// EnsureConfig loads and returns a config file. // // Any error will cause an immediate exit, with an error printed to Stderr. func EnsureConfig() *cfg.Config { yamlpath, err := gpath.Glide() if err != nil { msg.ExitCode(2) msg.Die("Failed to find %s file in directory tree: %s", gpath.GlideFile, err) } yml, err := ioutil.ReadFile(yamlpath) if err != nil { msg.ExitCode(2) msg.Die("Failed to load %s: %s", yamlpath, err) } conf, err := cfg.ConfigFromYaml(yml) if err != nil { msg.ExitCode(3) msg.Die("Failed to parse %s: %s", yamlpath, err) } b := filepath.Dir(yamlpath) buildContext, err := util.GetBuildContext() if err != nil { msg.Die("Failed to build an import context while ensuring config: %s", err) } cwd, err := os.Getwd() if err != nil { msg.Err("Unable to get the current working directory") } else { // Determining a package name requires a relative path b, err = filepath.Rel(b, cwd) if err == nil { name := buildContext.PackageName(b) if name != conf.Name { msg.Warn("The name listed in the config file (%s) does not match the current location (%s)", conf.Name, name) } } else { msg.Warn("Problem finding the config file path (%s) relative to the current directory (%s): %s", b, cwd, err) } } err = mirrors.Load() if err != nil { msg.Err("Unable to load mirrors: %s", err) } return conf }
// List lists all of the dependencies of the current project. // // Params: // - dir (string): basedir // - deep (bool): whether to do a deep scan or a shallow scan func List(basedir string, deep bool) { basedir, err := filepath.Abs(basedir) if err != nil { msg.Die("Could not read directory: %s", err) } r, err := dependency.NewResolver(basedir) if err != nil { msg.Die("Could not create a resolver: %s", err) } h := &dependency.DefaultMissingPackageHandler{Missing: []string{}, Gopath: []string{}} r.Handler = h sortable, err := r.ResolveLocal(deep) if err != nil { msg.Die("Error listing dependencies: %s", err) } msg.Info("Sorting...") sort.Strings(sortable) msg.Puts("INSTALLED packages:") for _, k := range sortable { v, err := filepath.Rel(basedir, k) if err != nil { //msg.Warn("Failed to Rel path: %s", err) v = k } msg.Puts("\t%s", v) } if len(h.Missing) > 0 { msg.Puts("\nMISSING packages:") for _, pkg := range h.Missing { msg.Puts("\t%s", pkg) } } if len(h.Gopath) > 0 { msg.Puts("\nGOPATH packages:") for _, pkg := range h.Gopath { msg.Puts("\t%s", pkg) } } }
// Install installs a vendor directory based on an existing Glide configuration. func Install(installer *repo.Installer) { base := "." // Ensure GOPATH EnsureGopath() EnsureVendorDir() conf := EnsureConfig() // Lockfile exists if !gpath.HasLock(base) { msg.Info("Lock file (glide.lock) does not exist. Performing update.") Update(installer, false) return } // Load lockfile lock, err := LoadLockfile(base, conf) if err != nil { msg.Die("Could not load lockfile.") } // Delete unused packages if installer.DeleteUnused { // It's unclear whether this should operate off of the lock, or off // of the glide.yaml file. I'd think that doing this based on the // lock would be much more reliable. dependency.DeleteUnused(conf) } // Install newConf, err := installer.Install(lock, conf) if err != nil { msg.Die("Failed to install: %s", err) } msg.Info("Setting references.") // Set reference if err := repo.SetReference(newConf); err != nil { msg.Error("Failed to set references: %s (Skip to cleanup)", err) } // VendoredCleanup. This should ONLY be run if UpdateVendored was specified. if installer.UpdateVendored { repo.VendoredCleanup(newConf) } }
// CacheClear clears the Glide cache func CacheClear() { l, err := cache.Location() if err != nil { msg.Die("Unable to clear the cache: %s", err) } err = os.RemoveAll(l) if err != nil { msg.Die("Unable to clear the cache: %s", err) } cache.SetupReset() err = cache.Setup() if err != nil { msg.Die("Unable to clear the cache: %s", err) } msg.Info("Glide cache has been cleared.") }
// ConcurrentUpdate takes a list of dependencies and updates in parallel. func ConcurrentUpdate(deps []*cfg.Dependency, i *Installer, c *cfg.Config) error { done := make(chan struct{}, concurrentWorkers) in := make(chan *cfg.Dependency, concurrentWorkers) var wg sync.WaitGroup var lock sync.Mutex var returnErr error for ii := 0; ii < concurrentWorkers; ii++ { go func(ch <-chan *cfg.Dependency) { for { select { case dep := <-ch: loc := dep.Remote() key, err := cache.Key(loc) if err != nil { msg.Die(err.Error()) } cache.Lock(key) if err := VcsUpdate(dep, i.Force, i.Updated); err != nil { msg.Err("Update failed for %s: %s\n", dep.Name, err) // Capture the error while making sure the concurrent // operations don't step on each other. lock.Lock() if returnErr == nil { returnErr = err } else { returnErr = cli.NewMultiError(returnErr, err) } lock.Unlock() } cache.Unlock(key) wg.Done() case <-done: return } } }(in) } for _, dep := range deps { if !c.HasIgnore(dep.Name) { wg.Add(1) in <- dep } } wg.Wait() // Close goroutines setting the version for ii := 0; ii < concurrentWorkers; ii++ { done <- struct{}{} } return returnErr }
func appendImports(deps []*cfg.Dependency, config *cfg.Config) { if len(deps) == 0 { msg.Info("No dependencies added.") return } //Append deps to existing dependencies. if err := config.AddImport(deps...); err != nil { msg.Die("Failed to add imports: %s", err) } }
// EnsureGopath fails if GOPATH is not set, or if $GOPATH/src is missing. // // Otherwise it returns the value of GOPATH. func EnsureGopath() string { gps := gpath.Gopaths() if len(gps) == 0 { msg.Die("$GOPATH is not set.") } for _, gp := range gps { _, err := os.Stat(path.Join(gp, "src")) if err != nil { msg.Warn("%s", err) continue } return gp } msg.Error("Could not find any of %s/src.\n", strings.Join(gps, "/src, ")) msg.Info("As of Glide 0.5/Go 1.5, this is required.\n") msg.Die("Wihtout src, cannot continue.") return "" }
// Tree prints a tree representing dependencies. func Tree(basedir string, showcore bool) { buildContext, err := util.GetBuildContext() if err != nil { msg.Die("Failed to get a build context: %s", err) } myName := buildContext.PackageName(basedir) if basedir == "." { var err error basedir, err = os.Getwd() if err != nil { msg.Die("Could not get working directory") } } msg.Puts(myName) l := list.New() l.PushBack(myName) tree.Display(buildContext, basedir, myName, 1, showcore, l) }
// EnsureConfig loads and returns a config file. // // Any error will cause an immediate exit, with an error printed to Stderr. func EnsureConfig() *cfg.Config { yamlpath, err := gpath.Glide() if err != nil { msg.ExitCode(2) msg.Die("Failed to find %s file in directory tree: %s", gpath.GlideFile, err) } yml, err := ioutil.ReadFile(yamlpath) if err != nil { msg.ExitCode(2) msg.Die("Failed to load %s: %s", yamlpath, err) } conf, err := cfg.ConfigFromYaml(yml) if err != nil { msg.ExitCode(3) msg.Die("Failed to parse %s: %s", yamlpath, err) } return conf }
// MirrorsSet sets a mirror to use func MirrorsSet(o, r, v string) error { if o == "" || r == "" { msg.Err("Both the original and mirror values are required") return nil } home := gpath.Home() op := filepath.Join(home, "mirrors.yaml") var ov *mirrors.Mirrors if _, err := os.Stat(op); os.IsNotExist(err) { msg.Info("No mirrors.yaml file exists. Creating new one") ov = &mirrors.Mirrors{ Repos: make(mirrors.MirrorRepos, 0), } } else { ov, err = mirrors.ReadMirrorsFile(op) if err != nil { msg.Die("Error reading existing mirrors.yaml file: %s", err) } } found := false for i, re := range ov.Repos { if re.Original == o { found = true msg.Info("%s found in mirrors. Replacing with new settings", o) ov.Repos[i].Repo = r ov.Repos[i].Vcs = v } } if !found { nr := &mirrors.MirrorRepo{ Original: o, Repo: r, Vcs: v, } ov.Repos = append(ov.Repos, nr) } msg.Info("%s being set to %s", o, r) err := ov.WriteFile(op) if err != nil { msg.Err("Error writing mirrors.yaml file: %s", err) } else { msg.Info("mirrors.yaml written with changes") } return nil }
// Create creates/initializes a new Glide repository. // // This will fail if a glide.yaml already exists. // // By default, this will scan the present source code directory for dependencies. // // If skipImport is set to true, this will not attempt to import from an existing // GPM, Godep, or GB project if one should exist. However, it will still attempt // to read the local source to determine required packages. func Create(base string, skipImport bool) { glidefile := gpath.GlideFile // Guard against overwrites. guardYAML(glidefile) // Guess deps conf := guessDeps(base, skipImport) // Write YAML if err := conf.WriteFile(glidefile); err != nil { msg.Die("Could not save %s: %s", glidefile, err) } }
// Tree prints a tree representing dependencies. func Tree(basedir string, showcore bool) { msg.Warn("The tree command is deprecated and will be removed in a future version") buildContext, err := util.GetBuildContext() if err != nil { msg.Die("Failed to get a build context: %s", err) } myName := buildContext.PackageName(basedir) if basedir == "." { var err error basedir, err = os.Getwd() if err != nil { msg.Die("Could not get working directory") } } msg.Puts(myName) l := list.New() l.PushBack(myName) tree.Display(buildContext, basedir, myName, 1, showcore, l) }