// 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") } }
// 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 }
// 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 }
// Remove removes a dependncy from the configuration. func Remove(packages []string, inst *repo.Installer) { base := gpath.Basepath() EnsureGopath() EnsureVendorDir() conf := EnsureConfig() glidefile, err := gpath.Glide() if err != nil { msg.Die("Could not find Glide file: %s", err) } msg.Info("Preparing to remove %d packages.", len(packages)) conf.Imports = rmDeps(packages, conf.Imports) conf.DevImports = rmDeps(packages, conf.DevImports) // Copy used to generate locks. confcopy := conf.Clone() confcopy.Imports = inst.List(confcopy) if err := repo.SetReference(confcopy, inst.ResolveTest); err != nil { msg.Err("Failed to set references: %s", err) } // TODO: Right now, there is no flag to enable this, so this will never be // run. I am not sure whether we should allow this in a rm op or not. if inst.UpdateVendored { repo.VendoredCleanup(confcopy) } // Write glide.yaml if err := conf.WriteFile(glidefile); err != nil { msg.Die("Failed to write glide YAML file: %s", err) } // Write glide lock writeLock(conf, confcopy, base) }
// Remove removes a dependncy from the configuration. func Remove(packages []string, inst *repo.Installer) { cache.SystemLock() base := gpath.Basepath() EnsureGopath() EnsureVendorDir() conf := EnsureConfig() glidefile, err := gpath.Glide() if err != nil { msg.Die("Could not find Glide file: %s", err) } msg.Info("Preparing to remove %d packages.", len(packages)) conf.Imports = rmDeps(packages, conf.Imports) conf.DevImports = rmDeps(packages, conf.DevImports) // Copy used to generate locks. confcopy := conf.Clone() //confcopy.Imports = inst.List(confcopy) if err := repo.SetReference(confcopy, inst.ResolveTest); err != nil { msg.Err("Failed to set references: %s", err) } err = inst.Export(confcopy) if err != nil { msg.Die("Unable to export dependencies to vendor directory: %s", err) } // Write glide.yaml if err := conf.WriteFile(glidefile); err != nil { msg.Die("Failed to write glide YAML file: %s", err) } // Write glide lock writeLock(conf, confcopy, base) }
// ConfigWizard reads configuration from a glide.yaml file and attempts to suggest // improvements. The wizard is interactive. func ConfigWizard(base string) { _, err := gpath.Glide() glidefile := gpath.GlideFile if err != nil { msg.Info("Unable to find a glide.yaml file. Would you like to create one now? Yes (Y) or No (N)") bres := msg.PromptUntilYorN() if bres { // Guess deps conf := guessDeps(base, false) // Write YAML if err := conf.WriteFile(glidefile); err != nil { msg.Die("Could not save %s: %s", glidefile, err) } } else { msg.Err("Unable to find configuration file. Please create configuration information to continue.") } } conf := EnsureConfig() err = cache.Setup() if err != nil { msg.Die("Problem setting up cache: %s", err) } msg.Info("Looking for dependencies to make suggestions on") msg.Info("--> Scanning for dependencies not using version ranges") msg.Info("--> Scanning for dependencies using commit ids") var deps []*cfg.Dependency for _, dep := range conf.Imports { if wizardLookInto(dep) { deps = append(deps, dep) } } for _, dep := range conf.DevImports { if wizardLookInto(dep) { deps = append(deps, dep) } } msg.Info("Gathering information on each dependency") msg.Info("--> This may take a moment. Especially on a codebase with many dependencies") msg.Info("--> Gathering release information for dependencies") msg.Info("--> Looking for dependency imports where versions are commit ids") for _, dep := range deps { wizardFindVersions(dep) } var changes int for _, dep := range deps { var remote string if dep.Repository != "" { remote = dep.Repository } else { remote = "https://" + dep.Name } // First check, ask if the tag should be used instead of the commit id for it. cur := cache.MemCurrent(remote) if cur != "" && cur != dep.Reference { wizardSugOnce() var dres bool asked, use, val := wizardOnce("current") if !use { dres = wizardAskCurrent(cur, dep) } if !asked { as := wizardRemember() wizardSetOnce("current", as, dres) } if asked && use { dres = val.(bool) } if dres { msg.Info("Updating %s to use the tag %s instead of commit id %s", dep.Name, cur, dep.Reference) dep.Reference = cur changes++ } } // Second check, if no version is being used and there's a semver release ask about latest. memlatest := cache.MemLatest(remote) if dep.Reference == "" && memlatest != "" { wizardSugOnce() var dres bool asked, use, val := wizardOnce("latest") if !use { dres = wizardAskLatest(memlatest, dep) } if !asked { as := wizardRemember() wizardSetOnce("latest", as, dres) } if asked && use { dres = val.(bool) } if dres { msg.Info("Updating %s to use the release %s instead of no release", dep.Name, memlatest) dep.Reference = memlatest changes++ } } // Third check, if the version is semver offer to use a range instead. sv, err := semver.NewVersion(dep.Reference) if err == nil { wizardSugOnce() var res string asked, use, val := wizardOnce("range") if !use { res = wizardAskRange(sv, dep) } if !asked { as := wizardRemember() wizardSetOnce("range", as, res) } if asked && use { res = val.(string) } if res == "m" { r := "^" + sv.String() msg.Info("Updating %s to use the range %s instead of commit id %s", dep.Name, r, dep.Reference) dep.Reference = r changes++ } else if res == "p" { r := "~" + sv.String() msg.Info("Updating %s to use the range %s instead of commit id %s", dep.Name, r, dep.Reference) dep.Reference = r changes++ } } } if changes > 0 { msg.Info("Configuration changes have been made. Would you like to write these") msg.Info("changes to your configuration file? Yes (Y) or No (N)") dres := msg.PromptUntilYorN() if dres { msg.Info("Writing updates to configuration file (%s)", glidefile) if err := conf.WriteFile(glidefile); err != nil { msg.Die("Could not save %s: %s", glidefile, err) } msg.Info("You can now edit the glide.yaml file.:") msg.Info("--> For more information on versions and ranges see https://glide.sh/docs/versions/") msg.Info("--> For details on additional metadata see https://glide.sh/docs/glide.yaml/") } else { msg.Warn("Change not written to configuration file") } } else { msg.Info("No proposed changes found. Have a nice day.") } }
// 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, strip, stripVendor, nonInteract bool) { if installer.UseCache { cache.SystemLock() } 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 count, err2 := addPkgsToConfig(conf, names, insecure, nonInteract); err2 != nil { msg.Die("Failed to get new packages: %s", err2) } else if count == 0 { msg.Warn("Nothing to do") return } // 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. err = installer.Checkout(conf, false) if err != nil { msg.Die("Failed to checkout packages: %s", err) } // 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.Err("Failed to set references: %s", err) } // VendoredCleanup // When stripping VCS happens this will happen as well. No need for double // effort. if installer.UpdateVendored && !strip { 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 if stripVendor { confcopy = godep.RemoveGodepSubpackages(confcopy) } writeLock(conf, confcopy, base) } else { msg.Warn("Skipping lockfile generation because full dependency tree is not being calculated") } if strip { msg.Info("Removing version control data from vendor directory...") gpath.StripVcs() } 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) } } }