github.com/n0needt0/glide@v0.0.0-20160325160517-844a77136d85/action/get.go (about)

     1  package action
     2  
     3  import (
     4  	"fmt"
     5  	"path/filepath"
     6  	"strings"
     7  
     8  	"github.com/Masterminds/glide/cfg"
     9  	"github.com/Masterminds/glide/godep"
    10  	"github.com/Masterminds/glide/msg"
    11  	gpath "github.com/Masterminds/glide/path"
    12  	"github.com/Masterminds/glide/repo"
    13  	"github.com/Masterminds/glide/util"
    14  )
    15  
    16  // Get fetches one or more dependencies and installs.
    17  //
    18  // This includes resolving dependency resolution and re-generating the lock file.
    19  func Get(names []string, installer *repo.Installer, insecure, skipRecursive, strip, stripVendor bool) {
    20  	base := gpath.Basepath()
    21  	EnsureGopath()
    22  	EnsureVendorDir()
    23  	conf := EnsureConfig()
    24  	glidefile, err := gpath.Glide()
    25  	if err != nil {
    26  		msg.Die("Could not find Glide file: %s", err)
    27  	}
    28  
    29  	// Add the packages to the config.
    30  	if count, err := addPkgsToConfig(conf, names, insecure); err != nil {
    31  		msg.Die("Failed to get new packages: %s", err)
    32  	} else if count == 0 {
    33  		msg.Warn("Nothing to do")
    34  		return
    35  	}
    36  
    37  	// Fetch the new packages. Can't resolve versions via installer.Update if
    38  	// get is called while the vendor/ directory is empty so we checkout
    39  	// everything.
    40  	installer.Checkout(conf, false)
    41  
    42  	// Prior to resolving dependencies we need to start working with a clone
    43  	// of the conf because we'll be making real changes to it.
    44  	confcopy := conf.Clone()
    45  
    46  	if !skipRecursive {
    47  		// Get all repos and update them.
    48  		// TODO: Can we streamline this in any way? The reason that we update all
    49  		// of the dependencies is that we need to re-negotiate versions. For example,
    50  		// if an existing dependency has the constraint >1.0 and this new package
    51  		// adds the constraint <2.0, then this may re-resolve the existing dependency
    52  		// to be between 1.0 and 2.0. But changing that dependency may then result
    53  		// in that dependency's dependencies changing... so we sorta do the whole
    54  		// thing to be safe.
    55  		err = installer.Update(confcopy)
    56  		if err != nil {
    57  			msg.Die("Could not update packages: %s", err)
    58  		}
    59  	}
    60  
    61  	// Set Reference
    62  	if err := repo.SetReference(confcopy); err != nil {
    63  		msg.Err("Failed to set references: %s", err)
    64  	}
    65  
    66  	// VendoredCleanup
    67  	// When stripping VCS happens this will happen as well. No need for double
    68  	// effort.
    69  	if installer.UpdateVendored && !strip {
    70  		repo.VendoredCleanup(confcopy)
    71  	}
    72  
    73  	// Write YAML
    74  	if err := conf.WriteFile(glidefile); err != nil {
    75  		msg.Die("Failed to write glide YAML file: %s", err)
    76  	}
    77  	if !skipRecursive {
    78  		// Write lock
    79  		if stripVendor {
    80  			confcopy = godep.RemoveGodepSubpackages(confcopy)
    81  		}
    82  		writeLock(conf, confcopy, base)
    83  	} else {
    84  		msg.Warn("Skipping lockfile generation because full dependency tree is not being calculated")
    85  	}
    86  
    87  	if strip {
    88  		msg.Info("Removing version control data from vendor directory...")
    89  		gpath.StripVcs()
    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 := cfg.NewLockfile(confcopy.Imports, hash)
   107  	if err := lock.WriteFile(filepath.Join(base, gpath.LockFile)); err != nil {
   108  		msg.Die("Failed to write glide lock file: %s", err)
   109  	}
   110  }
   111  
   112  // addPkgsToConfig adds the given packages to the config file.
   113  //
   114  // Along the way it:
   115  // - ensures that this package is not in the ignore list
   116  // - checks to see if this is already in the dependency list.
   117  // - splits version of of package name and adds the version attribute
   118  // - separates repo from packages
   119  // - sets up insecure repo URLs where necessary
   120  // - generates a list of subpackages
   121  func addPkgsToConfig(conf *cfg.Config, names []string, insecure bool) (int, error) {
   122  
   123  	msg.Info("Preparing to install %d package.", len(names))
   124  
   125  	numAdded := 0
   126  	for _, name := range names {
   127  		var version string
   128  		parts := strings.Split(name, "#")
   129  		if len(parts) > 1 {
   130  			name = parts[0]
   131  			version = parts[1]
   132  		}
   133  
   134  		root, subpkg := util.NormalizeName(name)
   135  		if len(root) == 0 {
   136  			return 0, fmt.Errorf("Package name is required for %q.", name)
   137  		}
   138  
   139  		if conf.HasDependency(root) {
   140  
   141  			// Check if the subpackage is present.
   142  			if subpkg != "" {
   143  				dep := conf.Imports.Get(root)
   144  				if dep.HasSubpackage(subpkg) {
   145  					msg.Warn("Package %q is already in glide.yaml. Skipping", name)
   146  				} else {
   147  					dep.Subpackages = append(dep.Subpackages, subpkg)
   148  					msg.Info("Adding sub-package %s to existing import %s", subpkg, root)
   149  					numAdded++
   150  				}
   151  			} else {
   152  				msg.Warn("Package %q is already in glide.yaml. Skipping", root)
   153  			}
   154  			continue
   155  		}
   156  
   157  		if conf.HasIgnore(root) {
   158  			msg.Warn("Package %q is set to be ignored in glide.yaml. Skipping", root)
   159  			continue
   160  		}
   161  
   162  		dep := &cfg.Dependency{
   163  			Name: root,
   164  		}
   165  
   166  		if version != "" {
   167  			dep.Reference = version
   168  		}
   169  
   170  		// When retriving from an insecure location set the repo to the
   171  		// insecure location.
   172  		if insecure {
   173  			dep.Repository = "http://" + root
   174  		}
   175  
   176  		if len(subpkg) > 0 {
   177  			dep.Subpackages = []string{subpkg}
   178  		}
   179  
   180  		if dep.Reference != "" {
   181  			msg.Info("Importing %s with the version %s", dep.Name, dep.Reference)
   182  		} else {
   183  			msg.Info("Importing %s", dep.Name)
   184  		}
   185  
   186  		conf.Imports = append(conf.Imports, dep)
   187  		numAdded++
   188  	}
   189  	return numAdded, nil
   190  }