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