github.com/golang/dep@v0.5.4/cmd/dep/init.go (about) 1 // Copyright 2016 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package main 6 7 import ( 8 "context" 9 "flag" 10 "log" 11 "os" 12 "path/filepath" 13 "time" 14 15 "github.com/golang/dep" 16 "github.com/golang/dep/gps" 17 "github.com/golang/dep/internal/fs" 18 "github.com/pkg/errors" 19 ) 20 21 const initShortHelp = `Set up a new Go project, or migrate an existing one` 22 const initLongHelp = ` 23 Initialize the project at filepath root by parsing its dependencies, writing 24 manifest and lock files, and vendoring the dependencies. If root isn't 25 specified, use the current directory. 26 27 When configuration for another dependency management tool is detected, it is 28 imported into the initial manifest and lock. Use the -skip-tools flag to 29 disable this behavior. The following external tools are supported: 30 glide, godep, vndr, govend, gb, gvt, govendor, glock. 31 32 Any dependencies that are not constrained by external configuration use the 33 GOPATH analysis below. 34 35 By default, the dependencies are resolved over the network. A version will be 36 selected from the versions available from the upstream source per the following 37 algorithm: 38 39 - Tags conforming to semver (sorted by semver rules) 40 - Default branch(es) (sorted lexicographically) 41 - Non-semver tags (sorted lexicographically) 42 43 An alternate mode can be activated by passing -gopath. In this mode, the version 44 of each dependency will reflect the current state of the GOPATH. If a dependency 45 doesn't exist in the GOPATH, a version will be selected based on the above 46 network version selection algorithm. 47 48 A Gopkg.toml file will be written with inferred version constraints for all 49 direct dependencies. Gopkg.lock will be written with precise versions, and 50 vendor/ will be populated with the precise versions written to Gopkg.lock. 51 ` 52 53 func (cmd *initCommand) Name() string { return "init" } 54 func (cmd *initCommand) Args() string { return "[root]" } 55 func (cmd *initCommand) ShortHelp() string { return initShortHelp } 56 func (cmd *initCommand) LongHelp() string { return initLongHelp } 57 func (cmd *initCommand) Hidden() bool { return false } 58 59 func (cmd *initCommand) Register(fs *flag.FlagSet) { 60 fs.BoolVar(&cmd.noExamples, "no-examples", false, "don't include example in Gopkg.toml") 61 fs.BoolVar(&cmd.skipTools, "skip-tools", false, "skip importing configuration from other dependency managers") 62 fs.BoolVar(&cmd.gopath, "gopath", false, "search in GOPATH for dependencies") 63 } 64 65 type initCommand struct { 66 noExamples bool 67 skipTools bool 68 gopath bool 69 } 70 71 func (cmd *initCommand) Run(ctx *dep.Ctx, args []string) error { 72 if len(args) > 1 { 73 return errors.Errorf("too many args (%d)", len(args)) 74 } 75 76 var root string 77 if len(args) == 0 { 78 root = ctx.WorkingDir 79 } else { 80 root = args[0] 81 if !filepath.IsAbs(args[0]) { 82 root = filepath.Join(ctx.WorkingDir, args[0]) 83 } 84 if err := os.MkdirAll(root, os.FileMode(0777)); err != nil { 85 return errors.Wrapf(err, "init failed: unable to create a directory at %s", root) 86 } 87 } 88 89 p, err := cmd.establishProjectAt(root, ctx) 90 if err != nil { 91 return err 92 } 93 94 sm, err := ctx.SourceManager() 95 if err != nil { 96 return errors.Wrap(err, "init failed: unable to create a source manager") 97 } 98 sm.UseDefaultSignalHandling() 99 defer sm.Release() 100 101 if ctx.Verbose { 102 ctx.Out.Println("Getting direct dependencies...") 103 } 104 105 directDeps, err := p.GetDirectDependencyNames(sm) 106 if err != nil { 107 return errors.Wrap(err, "init failed: unable to determine direct dependencies") 108 } 109 if ctx.Verbose { 110 ctx.Out.Printf("Checked %d directories for packages.\nFound %d direct dependencies.\n", len(p.RootPackageTree.Packages), len(directDeps)) 111 } 112 113 // Initialize with imported data, then fill in the gaps using the GOPATH 114 rootAnalyzer := newRootAnalyzer(cmd.skipTools, ctx, directDeps, sm) 115 p.Manifest, p.Lock, err = rootAnalyzer.InitializeRootManifestAndLock(root, p.ImportRoot) 116 if err != nil { 117 return errors.Wrap(err, "init failed: unable to prepare an initial manifest and lock for the solver") 118 } 119 120 // Set default prune options for go-tests and unused-packages 121 p.Manifest.PruneOptions.DefaultOptions = gps.PruneNestedVendorDirs | gps.PruneGoTestFiles | gps.PruneUnusedPackages 122 123 if cmd.gopath { 124 gs := newGopathScanner(ctx, directDeps, sm) 125 err = gs.InitializeRootManifestAndLock(p.Manifest, p.Lock) 126 if err != nil { 127 return errors.Wrap(err, "init failed: unable to scan the GOPATH for dependencies") 128 } 129 } 130 131 rootAnalyzer.skipTools = importDuringSolve() 132 copyLock := *p.Lock // Copy lock before solving. Use this to separate new lock projects from solved lock 133 134 params := gps.SolveParameters{ 135 RootDir: root, 136 RootPackageTree: p.RootPackageTree, 137 Manifest: p.Manifest, 138 Lock: p.Lock, 139 ProjectAnalyzer: rootAnalyzer, 140 } 141 142 if ctx.Verbose { 143 params.TraceLogger = ctx.Err 144 } 145 146 if err := ctx.ValidateParams(sm, params); err != nil { 147 return errors.Wrapf(err, "init failed: validation of solve parameters failed") 148 } 149 150 s, err := gps.Prepare(params, sm) 151 if err != nil { 152 return errors.Wrap(err, "init failed: unable to prepare the solver") 153 } 154 155 soln, err := s.Solve(context.TODO()) 156 if err != nil { 157 err = handleAllTheFailuresOfTheWorld(err) 158 return errors.Wrap(err, "init failed: unable to solve the dependency graph") 159 } 160 p.Lock = dep.LockFromSolution(soln, p.Manifest.PruneOptions) 161 162 rootAnalyzer.FinalizeRootManifestAndLock(p.Manifest, p.Lock, copyLock) 163 164 // Pass timestamp (yyyyMMddHHmmss format) as suffix to backup name. 165 vendorbak, err := dep.BackupVendor(filepath.Join(root, "vendor"), time.Now().Format("20060102150405")) 166 if err != nil { 167 return errors.Wrap(err, "init failed: first backup vendor/, delete it, and then retry the previous command: failed to backup existing vendor directory") 168 } 169 if vendorbak != "" { 170 ctx.Err.Printf("Old vendor backed up to %v", vendorbak) 171 } 172 173 sw, err := dep.NewSafeWriter(p.Manifest, nil, p.Lock, dep.VendorAlways, p.Manifest.PruneOptions, nil) 174 if err != nil { 175 return errors.Wrap(err, "init failed: unable to create a SafeWriter") 176 } 177 178 var logger *log.Logger 179 if ctx.Verbose { 180 logger = ctx.Err 181 } 182 if err := sw.Write(root, sm, !cmd.noExamples, logger); err != nil { 183 return errors.Wrap(err, "init failed: unable to write the manifest, lock and vendor directory to disk") 184 } 185 186 return nil 187 } 188 189 // establishProjectAt attempts to set up the provided path as the root for the 190 // project to be created. 191 // 192 // It checks for being within a GOPATH, that there is no pre-existing manifest 193 // and lock, and that we can successfully infer the root import path from 194 // GOPATH. 195 // 196 // If successful, it returns a dep.Project, ready for further use. 197 func (cmd *initCommand) establishProjectAt(root string, ctx *dep.Ctx) (*dep.Project, error) { 198 var err error 199 p := new(dep.Project) 200 if err = p.SetRoot(root); err != nil { 201 return nil, errors.Wrapf(err, "init failed: unable to set the root project to %s", root) 202 } 203 204 ctx.GOPATH, err = ctx.DetectProjectGOPATH(p) 205 if err != nil { 206 return nil, errors.Wrapf(err, "init failed: unable to detect the containing GOPATH") 207 } 208 209 mf := filepath.Join(root, dep.ManifestName) 210 lf := filepath.Join(root, dep.LockName) 211 212 mok, err := fs.IsRegular(mf) 213 if err != nil { 214 return nil, errors.Wrapf(err, "init failed: unable to check for an existing manifest at %s", mf) 215 } 216 if mok { 217 return nil, errors.Errorf("init aborted: manifest already exists at %s", mf) 218 } 219 220 lok, err := fs.IsRegular(lf) 221 if err != nil { 222 return nil, errors.Wrapf(err, "init failed: unable to check for an existing lock at %s", lf) 223 } 224 if lok { 225 return nil, errors.Errorf("invalid aborted: lock already exists at %s", lf) 226 } 227 228 ip, err := ctx.ImportForAbs(root) 229 if err != nil { 230 return nil, errors.Wrapf(err, "init failed: unable to determine the import path for the root project %s", root) 231 } 232 p.ImportRoot = gps.ProjectRoot(ip) 233 234 return p, nil 235 }