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