github.com/MealCraft/glide@v0.13.4/action/get.go (about)

     1  package action
     2  
     3  import (
     4  	"fmt"
     5  	"path/filepath"
     6  	"strings"
     7  
     8  	"github.com/Masterminds/glide/cache"
     9  	"github.com/Masterminds/glide/cfg"
    10  	"github.com/Masterminds/glide/godep"
    11  	"github.com/Masterminds/glide/msg"
    12  	gpath "github.com/Masterminds/glide/path"
    13  	"github.com/Masterminds/glide/repo"
    14  	"github.com/Masterminds/glide/util"
    15  	"github.com/Masterminds/semver"
    16  )
    17  
    18  // Get fetches one or more dependencies and installs.
    19  //
    20  // This includes resolving dependency resolution and re-generating the lock file.
    21  func Get(names []string, installer *repo.Installer, insecure, skipRecursive, stripVendor, nonInteract, testDeps bool) {
    22  	cache.SystemLock()
    23  
    24  	base := gpath.Basepath()
    25  	EnsureGopath()
    26  	EnsureVendorDir()
    27  	conf := EnsureConfig()
    28  	glidefile, err := gpath.Glide()
    29  	if err != nil {
    30  		msg.Die("Could not find Glide file: %s", err)
    31  	}
    32  
    33  	// Add the packages to the config.
    34  	if count, err2 := addPkgsToConfig(conf, names, insecure, nonInteract, testDeps); err2 != nil {
    35  		msg.Die("Failed to get new packages: %s", err2)
    36  	} else if count == 0 {
    37  		msg.Warn("Nothing to do")
    38  		return
    39  	}
    40  
    41  	// Fetch the new packages. Can't resolve versions via installer.Update if
    42  	// get is called while the vendor/ directory is empty so we checkout
    43  	// everything.
    44  	err = installer.Checkout(conf)
    45  	if err != nil {
    46  		msg.Die("Failed to checkout packages: %s", err)
    47  	}
    48  
    49  	// Prior to resolving dependencies we need to start working with a clone
    50  	// of the conf because we'll be making real changes to it.
    51  	confcopy := conf.Clone()
    52  
    53  	if !skipRecursive {
    54  		// Get all repos and update them.
    55  		// TODO: Can we streamline this in any way? The reason that we update all
    56  		// of the dependencies is that we need to re-negotiate versions. For example,
    57  		// if an existing dependency has the constraint >1.0 and this new package
    58  		// adds the constraint <2.0, then this may re-resolve the existing dependency
    59  		// to be between 1.0 and 2.0. But changing that dependency may then result
    60  		// in that dependency's dependencies changing... so we sorta do the whole
    61  		// thing to be safe.
    62  		err = installer.Update(confcopy)
    63  		if err != nil {
    64  			msg.Die("Could not update packages: %s", err)
    65  		}
    66  	}
    67  
    68  	// Set Reference
    69  	if err := repo.SetReference(confcopy, installer.ResolveTest); err != nil {
    70  		msg.Err("Failed to set references: %s", err)
    71  	}
    72  
    73  	err = installer.Export(confcopy)
    74  	if err != nil {
    75  		msg.Die("Unable to export dependencies to vendor directory: %s", err)
    76  	}
    77  
    78  	// Write YAML
    79  	if err := conf.WriteFile(glidefile); err != nil {
    80  		msg.Die("Failed to write glide YAML file: %s", err)
    81  	}
    82  	if !skipRecursive {
    83  		// Write lock
    84  		if stripVendor {
    85  			confcopy = godep.RemoveGodepSubpackages(confcopy)
    86  		}
    87  		writeLock(conf, confcopy, base)
    88  	} else {
    89  		msg.Warn("Skipping lockfile generation because full dependency tree is not being calculated")
    90  	}
    91  
    92  	if stripVendor {
    93  		msg.Info("Removing nested vendor and Godeps/_workspace directories...")
    94  		err := gpath.StripVendor()
    95  		if err != nil {
    96  			msg.Err("Unable to strip vendor directories: %s", err)
    97  		}
    98  	}
    99  }
   100  
   101  func writeLock(conf, confcopy *cfg.Config, base string) {
   102  	hash, err := conf.Hash()
   103  	if err != nil {
   104  		msg.Die("Failed to generate config hash. Unable to generate lock file.")
   105  	}
   106  	lock, err := cfg.NewLockfile(confcopy.Imports, confcopy.DevImports, hash)
   107  	if err != nil {
   108  		msg.Die("Failed to generate lock file: %s", err)
   109  	}
   110  	if err := lock.WriteFile(filepath.Join(base, gpath.LockFile)); err != nil {
   111  		msg.Die("Failed to write glide lock file: %s", err)
   112  	}
   113  }
   114  
   115  // addPkgsToConfig adds the given packages to the config file.
   116  //
   117  // Along the way it:
   118  // - ensures that this package is not in the ignore list
   119  // - checks to see if this is already in the dependency list.
   120  // - splits version of of package name and adds the version attribute
   121  // - separates repo from packages
   122  // - sets up insecure repo URLs where necessary
   123  // - generates a list of subpackages
   124  func addPkgsToConfig(conf *cfg.Config, names []string, insecure, nonInteract, testDeps bool) (int, error) {
   125  
   126  	if len(names) == 1 {
   127  		msg.Info("Preparing to install %d package.", len(names))
   128  	} else {
   129  		msg.Info("Preparing to install %d packages.", len(names))
   130  	}
   131  	numAdded := 0
   132  	for _, name := range names {
   133  		var version string
   134  		parts := strings.Split(name, "#")
   135  		if len(parts) > 1 {
   136  			name = parts[0]
   137  			version = parts[1]
   138  		}
   139  
   140  		msg.Info("Attempting to get package %s", name)
   141  
   142  		root, subpkg := util.NormalizeName(name)
   143  		if len(root) == 0 {
   144  			return 0, fmt.Errorf("Package name is required for %q.", name)
   145  		}
   146  
   147  		if conf.HasDependency(root) {
   148  
   149  			var moved bool
   150  			var dep *cfg.Dependency
   151  			// Move from DevImports to Imports
   152  			if !testDeps && !conf.Imports.Has(root) && conf.DevImports.Has(root) {
   153  				dep = conf.DevImports.Get(root)
   154  				conf.Imports = append(conf.Imports, dep)
   155  				conf.DevImports = conf.DevImports.Remove(root)
   156  				moved = true
   157  				numAdded++
   158  				msg.Info("--> Moving %s from testImport to import", root)
   159  			} else if testDeps && conf.Imports.Has(root) {
   160  				msg.Warn("--> Test dependency %s already listed as import", root)
   161  			}
   162  
   163  			// Check if the subpackage is present.
   164  			if subpkg != "" {
   165  				if dep == nil {
   166  					dep = conf.Imports.Get(root)
   167  					if dep == nil && testDeps {
   168  						dep = conf.DevImports.Get(root)
   169  					}
   170  				}
   171  				if dep.HasSubpackage(subpkg) {
   172  					if !moved {
   173  						msg.Warn("--> Package %q is already in glide.yaml. Skipping", name)
   174  					}
   175  				} else {
   176  					dep.Subpackages = append(dep.Subpackages, subpkg)
   177  					msg.Info("--> Adding sub-package %s to existing import %s", subpkg, root)
   178  					numAdded++
   179  				}
   180  			} else if !moved {
   181  				msg.Warn("--> Package %q is already in glide.yaml. Skipping", root)
   182  			}
   183  			continue
   184  		}
   185  
   186  		if conf.HasIgnore(root) {
   187  			msg.Warn("--> Package %q is set to be ignored in glide.yaml. Skipping", root)
   188  			continue
   189  		}
   190  
   191  		dep := &cfg.Dependency{
   192  			Name: root,
   193  		}
   194  
   195  		// When retriving from an insecure location set the repo to the
   196  		// insecure location.
   197  		if insecure {
   198  			dep.Repository = "http://" + root
   199  		}
   200  
   201  		if version != "" {
   202  			dep.Reference = version
   203  		} else if !nonInteract {
   204  			getWizard(dep)
   205  		}
   206  
   207  		if len(subpkg) > 0 {
   208  			dep.Subpackages = []string{subpkg}
   209  		}
   210  
   211  		if dep.Reference != "" {
   212  			msg.Info("--> Adding %s to your configuration with the version %s", dep.Name, dep.Reference)
   213  		} else {
   214  			msg.Info("--> Adding %s to your configuration", dep.Name)
   215  		}
   216  
   217  		if testDeps {
   218  			conf.DevImports = append(conf.DevImports, dep)
   219  		} else {
   220  			conf.Imports = append(conf.Imports, dep)
   221  		}
   222  		numAdded++
   223  	}
   224  	return numAdded, nil
   225  }
   226  
   227  func getWizard(dep *cfg.Dependency) {
   228  	remote := dep.Remote()
   229  
   230  	// Lookup dependency info and store in cache.
   231  	msg.Info("--> Gathering release information for %s", dep.Name)
   232  	wizardFindVersions(dep)
   233  
   234  	memlatest := cache.MemLatest(remote)
   235  	if memlatest != "" {
   236  		dres := wizardAskLatest(memlatest, dep)
   237  		if dres {
   238  			dep.Reference = memlatest
   239  
   240  			sv, err := semver.NewVersion(dep.Reference)
   241  			if err == nil {
   242  				res := wizardAskRange(sv, dep)
   243  				if res == "m" {
   244  					dep.Reference = "^" + sv.String()
   245  				} else if res == "p" {
   246  					dep.Reference = "~" + sv.String()
   247  				}
   248  			}
   249  		}
   250  	}
   251  }