|  | package action | 
|  |  | 
|  | import ( | 
|  | "fmt" | 
|  | "log" | 
|  | "os" | 
|  | "path/filepath" | 
|  | "strings" | 
|  |  | 
|  | "github.com/Masterminds/glide/cache" | 
|  | "github.com/Masterminds/glide/cfg" | 
|  | "github.com/Masterminds/glide/dependency" | 
|  | "github.com/Masterminds/glide/msg" | 
|  | gpath "github.com/Masterminds/glide/path" | 
|  | "github.com/Masterminds/glide/repo" | 
|  | "github.com/Masterminds/glide/util" | 
|  | "github.com/Masterminds/semver" | 
|  | "github.com/sdboyer/gps" | 
|  | ) | 
|  |  | 
|  | // Get fetches one or more dependencies and installs. | 
|  | // | 
|  | // This includes a solver run and re-generating the lock file. | 
|  | func Get(names []string, installer *repo.Installer, stripVendor, nonInteract bool) { | 
|  | base := gpath.Basepath() | 
|  | EnsureGopath() | 
|  | EnsureVendorDir() | 
|  | conf := EnsureConfig() | 
|  |  | 
|  | glidefile, err := gpath.Glide() | 
|  | if err != nil { | 
|  | msg.Die("Could not find Glide file: %s", err) | 
|  | } | 
|  |  | 
|  | vend, err := gpath.Vendor() | 
|  | if err != nil { | 
|  | msg.Die("Could not find the vendor dir: %s", err) | 
|  | } | 
|  |  | 
|  | rd := filepath.Dir(glidefile) | 
|  | rt, err := gps.ListPackages(rd, conf.Name) | 
|  | if err != nil { | 
|  | msg.Die("Error while scanning project imports: %s", err) | 
|  | } | 
|  |  | 
|  | params := gps.SolveParameters{ | 
|  | RootDir:         rd, | 
|  | RootPackageTree: rt, | 
|  | Manifest:        conf, | 
|  | Trace:           true, | 
|  | TraceLogger:     log.New(os.Stdout, "", 0), | 
|  | } | 
|  |  | 
|  | // We load the lock file early and bail out if there's a problem, because we | 
|  | // don't want a get to just update all deps without the user explictly | 
|  | // making that choice. | 
|  | if gpath.HasLock(base) { | 
|  | params.Lock, _, err = loadLockfile(base, conf) | 
|  | if err != nil { | 
|  | msg.Err("Could not load lockfile; aborting get. Other dependency versions cannot be preserved without an invalid lock file . Error was: %s", err) | 
|  | return | 
|  | } | 
|  | } | 
|  |  | 
|  | // Create the SourceManager for this run | 
|  | sm, err := gps.NewSourceManager(dependency.Analyzer{}, filepath.Join(installer.Home, "cache")) | 
|  | defer sm.Release() | 
|  | if err != nil { | 
|  | msg.Err(err.Error()) | 
|  | return | 
|  | } | 
|  |  | 
|  | // Now, with the easy/fast errors out of the way, dive into adding the new | 
|  | // deps to the manifest. | 
|  |  | 
|  | // Add the packages to the config. | 
|  | //if count, err2 := addPkgsToConfig(conf, names, insecure, nonInteract, testDeps); err2 != nil { | 
|  | if count, err2 := addPkgsToConfig(conf, names, false, nonInteract, false); err2 != nil { | 
|  | msg.Die("Failed to get new packages: %s", err2) | 
|  | } else if count == 0 { | 
|  | msg.Warn("Nothing to do") | 
|  | return | 
|  | } | 
|  |  | 
|  | // Prepare a solver. This validates our params. | 
|  | s, err := gps.Prepare(params, sm) | 
|  | if err != nil { | 
|  | msg.Err("Aborted get - could not set up solver to reconcile dependencies: %s", err) | 
|  | return | 
|  | } | 
|  |  | 
|  | r, err := s.Solve() | 
|  | if err != nil { | 
|  | // TODO better error handling | 
|  | msg.Err("Failed to find a solution for all new dependencies: %s", err.Error()) | 
|  | return | 
|  | } | 
|  |  | 
|  | // Solve succeeded. Write out the yaml, lock, and vendor to a tmpdir, then mv | 
|  | // them all into place iff all the writes worked | 
|  |  | 
|  | gw := safeGroupWriter{ | 
|  | conf:        conf, | 
|  | lock:        params.Lock.(*cfg.Lockfile), | 
|  | resultLock:  r, | 
|  | sm:          sm, | 
|  | glidefile:   glidefile, | 
|  | vendor:      vend, | 
|  | stripVendor: stripVendor, | 
|  | } | 
|  |  | 
|  | err = gw.writeAllSafe() | 
|  | if err != nil { | 
|  | msg.Err(err.Error()) | 
|  | } | 
|  | } | 
|  |  | 
|  | 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, err := cfg.NewLockfile(confcopy.Imports, confcopy.DevImports, hash) | 
|  | if err != nil { | 
|  | msg.Die("Failed to generate lock file: %s", err) | 
|  | } | 
|  | if err := lock.WriteFile(filepath.Join(base, gpath.LockFile)); err != nil { | 
|  | msg.Die("Failed to write glide lock file: %s", err) | 
|  | } | 
|  | } | 
|  |  | 
|  | // addPkgsToConfig adds the given packages to the config file. | 
|  | // | 
|  | // Along the way it: | 
|  | // - ensures that this package is not in the ignore list | 
|  | // - checks to see if this is already in the dependency list. | 
|  | // - splits version of of package name and adds the version attribute | 
|  | // - separates repo from packages | 
|  | // - sets up insecure repo URLs where necessary | 
|  | // - generates a list of subpackages | 
|  | func addPkgsToConfig(conf *cfg.Config, names []string, insecure, nonInteract, testDeps bool) (int, error) { | 
|  | // TODO refactor this to take and use a gps.SourceManager | 
|  | if len(names) == 1 { | 
|  | msg.Info("Preparing to install %d package.", len(names)) | 
|  | } else { | 
|  | msg.Info("Preparing to install %d packages.", len(names)) | 
|  | } | 
|  | numAdded := 0 | 
|  | for _, name := range names { | 
|  | var version string | 
|  | parts := strings.Split(name, "#") | 
|  | if len(parts) > 1 { | 
|  | name = parts[0] | 
|  | version = parts[1] | 
|  | } | 
|  |  | 
|  | msg.Info("Attempting to get package %s", name) | 
|  |  | 
|  | root, _ := util.NormalizeName(name) | 
|  | if len(root) == 0 { | 
|  | return 0, fmt.Errorf("Package name is required for %q.", name) | 
|  | } | 
|  |  | 
|  | if conf.HasDependency(root) { | 
|  |  | 
|  | var moved bool | 
|  | var dep *cfg.Dependency | 
|  | // Move from DevImports to Imports | 
|  | if !testDeps && !conf.Imports.Has(root) && conf.DevImports.Has(root) { | 
|  | dep = conf.DevImports.Get(root) | 
|  | conf.Imports = append(conf.Imports, dep) | 
|  | conf.DevImports = conf.DevImports.Remove(root) | 
|  | moved = true | 
|  | numAdded++ | 
|  | msg.Info("--> Moving %s from testImport to import", root) | 
|  | } else if testDeps && conf.Imports.Has(root) { | 
|  | msg.Warn("--> Test dependency %s already listed as import", root) | 
|  | } | 
|  |  | 
|  | if !moved { | 
|  | msg.Warn("--> Package %q is already in glide.yaml. Skipping", root) | 
|  | } | 
|  | continue | 
|  | } | 
|  |  | 
|  | if conf.HasIgnore(root) { | 
|  | msg.Warn("--> Package %q is set to be ignored in glide.yaml. Skipping", root) | 
|  | continue | 
|  | } | 
|  |  | 
|  | dep := &cfg.Dependency{ | 
|  | Name: root, | 
|  | } | 
|  |  | 
|  | // When retriving from an insecure location set the repo to the | 
|  | // insecure location. | 
|  | if insecure { | 
|  | dep.Repository = "http://" + root | 
|  | } | 
|  |  | 
|  | if version != "" { | 
|  | // TODO(sdboyer) set the right type...what is that here? | 
|  | dep.Version = version | 
|  | dep.Branch = "" // just to be sure | 
|  | } else if !nonInteract { | 
|  | getWizard(dep) | 
|  | } | 
|  |  | 
|  | if !dep.IsUnconstrained() { | 
|  | msg.Info("--> Adding %s to your configuration with the version %s", dep.Name, dep.GetConstraint()) | 
|  | } else { | 
|  | msg.Info("--> Adding %s to your configuration", dep.Name) | 
|  | } | 
|  |  | 
|  | if testDeps { | 
|  | conf.DevImports = append(conf.DevImports, dep) | 
|  | } else { | 
|  | conf.Imports = append(conf.Imports, dep) | 
|  | } | 
|  | numAdded++ | 
|  | } | 
|  | return numAdded, nil | 
|  | } | 
|  |  | 
|  | func getWizard(dep *cfg.Dependency) { | 
|  | remote := dep.Remote() | 
|  |  | 
|  | // Lookup dependency info and store in cache. | 
|  | msg.Info("--> Gathering release information for %s", dep.Name) | 
|  | wizardFindVersions(dep) | 
|  |  | 
|  | memlatest := cache.MemLatest(remote) | 
|  | if memlatest != "" { | 
|  | dres := wizardAskLatest(memlatest, dep) | 
|  | if dres { | 
|  | dep.Version = memlatest | 
|  |  | 
|  | sv, err := semver.NewVersion(memlatest) | 
|  | if err != nil { | 
|  | res := wizardAskRange(sv, dep) | 
|  | if res == "m" { | 
|  | dep.Version = "^" + memlatest | 
|  | } else if res == "p" { | 
|  | dep.Version = "~" + memlatest | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  | } |