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 }