1
2
3
4
5
6 package get
7
8 import (
9 "context"
10 "fmt"
11 "os"
12 "path/filepath"
13 "runtime"
14 "strings"
15
16 "cmd/go/internal/base"
17 "cmd/go/internal/cfg"
18 "cmd/go/internal/load"
19 "cmd/go/internal/search"
20 "cmd/go/internal/str"
21 "cmd/go/internal/vcs"
22 "cmd/go/internal/web"
23 "cmd/go/internal/work"
24
25 "golang.org/x/mod/module"
26 )
27
28 var CmdGet = &base.Command{
29 UsageLine: "go get [-d] [-f] [-t] [-u] [-v] [-fix] [build flags] [packages]",
30 Short: "download and install packages and dependencies",
31 Long: `
32 Get downloads the packages named by the import paths, along with their
33 dependencies. It then installs the named packages, like 'go install'.
34
35 The -d flag instructs get to stop after downloading the packages; that is,
36 it instructs get not to install the packages.
37
38 The -f flag, valid only when -u is set, forces get -u not to verify that
39 each package has been checked out from the source control repository
40 implied by its import path. This can be useful if the source is a local fork
41 of the original.
42
43 The -fix flag instructs get to run the fix tool on the downloaded packages
44 before resolving dependencies or building the code.
45
46 The -t flag instructs get to also download the packages required to build
47 the tests for the specified packages.
48
49 The -u flag instructs get to use the network to update the named packages
50 and their dependencies. By default, get uses the network to check out
51 missing packages but does not use it to look for updates to existing packages.
52
53 The -v flag enables verbose progress and debug output.
54
55 Get also accepts build flags to control the installation. See 'go help build'.
56
57 When checking out a new package, get creates the target directory
58 GOPATH/src/<import-path>. If the GOPATH contains multiple entries,
59 get uses the first one. For more details see: 'go help gopath'.
60
61 When checking out or updating a package, get looks for a branch or tag
62 that matches the locally installed version of Go. The most important
63 rule is that if the local installation is running version "go1", get
64 searches for a branch or tag named "go1". If no such version exists
65 it retrieves the default branch of the package.
66
67 When go get checks out or updates a Git repository,
68 it also updates any git submodules referenced by the repository.
69
70 Get never checks out or updates code stored in vendor directories.
71
72 For more about specifying packages, see 'go help packages'.
73
74 For more about how 'go get' finds source code to
75 download, see 'go help importpath'.
76
77 This text describes the behavior of get when using GOPATH
78 to manage source code and dependencies.
79 If instead the go command is running in module-aware mode,
80 the details of get's flags and effects change, as does 'go help get'.
81 See 'go help modules' and 'go help module-get'.
82
83 See also: go build, go install, go clean.
84 `,
85 }
86
87 var HelpGopathGet = &base.Command{
88 UsageLine: "gopath-get",
89 Short: "legacy GOPATH go get",
90 Long: `
91 The 'go get' command changes behavior depending on whether the
92 go command is running in module-aware mode or legacy GOPATH mode.
93 This help text, accessible as 'go help gopath-get' even in module-aware mode,
94 describes 'go get' as it operates in legacy GOPATH mode.
95
96 Usage: ` + CmdGet.UsageLine + `
97 ` + CmdGet.Long,
98 }
99
100 var (
101 getD = CmdGet.Flag.Bool("d", false, "")
102 getF = CmdGet.Flag.Bool("f", false, "")
103 getT = CmdGet.Flag.Bool("t", false, "")
104 getU = CmdGet.Flag.Bool("u", false, "")
105 getFix = CmdGet.Flag.Bool("fix", false, "")
106 getInsecure = CmdGet.Flag.Bool("insecure", false, "")
107 )
108
109 func init() {
110 work.AddBuildFlags(CmdGet, work.OmitModFlag|work.OmitModCommonFlags)
111 CmdGet.Run = runGet
112 }
113
114 func runGet(ctx context.Context, cmd *base.Command, args []string) {
115 if cfg.ModulesEnabled {
116
117 base.Fatalf("go get: modules not implemented")
118 }
119
120 work.BuildInit()
121
122 if *getF && !*getU {
123 base.Fatalf("go get: cannot use -f flag without -u")
124 }
125 if *getInsecure {
126 base.Fatalf("go get: -insecure flag is no longer supported; use GOINSECURE instead")
127 }
128
129
130
131
132
133
134
135 if os.Getenv("GIT_TERMINAL_PROMPT") == "" {
136 os.Setenv("GIT_TERMINAL_PROMPT", "0")
137 }
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155 if os.Getenv("GIT_SSH") == "" && os.Getenv("GIT_SSH_COMMAND") == "" {
156 os.Setenv("GIT_SSH_COMMAND", "ssh -o ControlMaster=no -o BatchMode=yes")
157 }
158
159
160
161
162 if os.Getenv("GCM_INTERACTIVE") == "" {
163 os.Setenv("GCM_INTERACTIVE", "never")
164 }
165
166
167 var stk load.ImportStack
168 mode := 0
169 if *getT {
170 mode |= load.GetTestDeps
171 }
172 for _, pkg := range downloadPaths(args) {
173 download(pkg, nil, &stk, mode)
174 }
175 base.ExitIfErrors()
176
177
178
179
180
181
182
183
184 load.ClearPackageCache()
185
186 pkgs := load.PackagesAndErrors(ctx, load.PackageOpts{}, args)
187 load.CheckPackageErrors(pkgs)
188
189
190 if *getD {
191
192
193
194 return
195 }
196
197 work.InstallPackages(ctx, args, pkgs)
198 }
199
200
201
202
203
204
205 func downloadPaths(patterns []string) []string {
206 for _, arg := range patterns {
207 if strings.Contains(arg, "@") {
208 base.Fatalf("go: can only use path@version syntax with 'go get' and 'go install' in module-aware mode")
209 continue
210 }
211
212
213
214
215 if strings.HasSuffix(arg, ".go") {
216 if !strings.Contains(arg, "/") {
217 base.Errorf("go get %s: arguments must be package or module paths", arg)
218 continue
219 }
220 if fi, err := os.Stat(arg); err == nil && !fi.IsDir() {
221 base.Errorf("go get: %s exists as a file, but 'go get' requires package arguments", arg)
222 }
223 }
224 }
225 base.ExitIfErrors()
226
227 var pkgs []string
228 for _, m := range search.ImportPathsQuiet(patterns) {
229 if len(m.Pkgs) == 0 && strings.Contains(m.Pattern(), "...") {
230 pkgs = append(pkgs, m.Pattern())
231 } else {
232 pkgs = append(pkgs, m.Pkgs...)
233 }
234 }
235 return pkgs
236 }
237
238
239
240
241
242 var downloadCache = map[string]bool{}
243
244
245
246
247
248
249 var downloadRootCache = map[string]bool{}
250
251
252
253 func download(arg string, parent *load.Package, stk *load.ImportStack, mode int) {
254 if mode&load.ResolveImport != 0 {
255
256 panic("internal error: download mode has useVendor set")
257 }
258 load1 := func(path string, mode int) *load.Package {
259 if parent == nil {
260 mode := 0
261 return load.LoadImport(context.TODO(), load.PackageOpts{}, path, base.Cwd(), nil, stk, nil, mode)
262 }
263 return load.LoadImport(context.TODO(), load.PackageOpts{}, path, parent.Dir, parent, stk, nil, mode|load.ResolveModule)
264 }
265
266 p := load1(arg, mode)
267 if p.Error != nil && p.Error.Hard {
268 base.Errorf("%s", p.Error)
269 return
270 }
271
272
273
274
275
276
277
278
279
280 arg = p.ImportPath
281
282
283 if p.Standard {
284 return
285 }
286
287
288
289
290 if downloadCache[arg] && mode&load.GetTestDeps == 0 {
291 return
292 }
293 downloadCache[arg] = true
294
295 pkgs := []*load.Package{p}
296 wildcardOkay := len(*stk) == 0
297 isWildcard := false
298
299
300 if p.Dir == "" || *getU {
301
302 stk.Push(arg)
303 err := downloadPackage(p)
304 if err != nil {
305 base.Errorf("%s", &load.PackageError{ImportStack: stk.Copy(), Err: err})
306 stk.Pop()
307 return
308 }
309 stk.Pop()
310
311 args := []string{arg}
312
313
314
315 if wildcardOkay && strings.Contains(arg, "...") {
316 match := search.NewMatch(arg)
317 if match.IsLocal() {
318 match.MatchDirs()
319 args = match.Dirs
320 } else {
321 match.MatchPackages()
322 args = match.Pkgs
323 }
324 for _, err := range match.Errs {
325 base.Errorf("%s", err)
326 }
327 isWildcard = true
328 }
329
330
331
332 load.ClearPackageCachePartial(args)
333
334 pkgs = pkgs[:0]
335 for _, arg := range args {
336
337
338
339 p := load1(arg, mode)
340 if p.Error != nil {
341 base.Errorf("%s", p.Error)
342 continue
343 }
344 pkgs = append(pkgs, p)
345 }
346 }
347
348
349
350 for _, p := range pkgs {
351 if *getFix {
352 files := base.RelPaths(p.InternalAllGoFiles())
353 base.Run(cfg.BuildToolexec, str.StringList(base.Tool("fix"), files))
354
355
356 p = load.ReloadPackageNoFlags(arg, stk)
357 if p.Error != nil {
358 base.Errorf("%s", p.Error)
359 return
360 }
361 }
362
363 if isWildcard {
364
365
366 stk.Push(p.ImportPath)
367 }
368
369
370 imports := p.Imports
371 if mode&load.GetTestDeps != 0 {
372
373
374
375 imports = str.StringList(imports, p.TestImports, p.XTestImports)
376 }
377 for i, path := range imports {
378 if path == "C" {
379 continue
380 }
381
382
383
384 orig := path
385 if i < len(p.Internal.Build.Imports) {
386 orig = p.Internal.Build.Imports[i]
387 }
388 if j, ok := load.FindVendor(orig); ok {
389 stk.Push(path)
390 err := &load.PackageError{
391 ImportStack: stk.Copy(),
392 Err: load.ImportErrorf(path, "%s must be imported as %s", path, path[j+len("vendor/"):]),
393 }
394 stk.Pop()
395 base.Errorf("%s", err)
396 continue
397 }
398
399
400
401
402 if i >= len(p.Imports) {
403 path = load.ResolveImportPath(p, path)
404 }
405 download(path, p, stk, 0)
406 }
407
408 if isWildcard {
409 stk.Pop()
410 }
411 }
412 }
413
414
415
416 func downloadPackage(p *load.Package) error {
417 var (
418 vcsCmd *vcs.Cmd
419 repo, rootPath string
420 err error
421 blindRepo bool
422 )
423
424
425
426
427
428
429 importPrefix := p.ImportPath
430 if i := strings.Index(importPrefix, "..."); i >= 0 {
431 slash := strings.LastIndexByte(importPrefix[:i], '/')
432 if slash < 0 {
433 return fmt.Errorf("cannot expand ... in %q", p.ImportPath)
434 }
435 importPrefix = importPrefix[:slash]
436 }
437 if err := checkImportPath(importPrefix); err != nil {
438 return fmt.Errorf("%s: invalid import path: %v", p.ImportPath, err)
439 }
440 security := web.SecureOnly
441 if module.MatchPrefixPatterns(cfg.GOINSECURE, importPrefix) {
442 security = web.Insecure
443 }
444
445 if p.Internal.Build.SrcRoot != "" {
446
447 vcsCmd, rootPath, err = vcs.FromDir(p.Dir, p.Internal.Build.SrcRoot)
448 if err != nil {
449 return err
450 }
451 repo = "<local>"
452
453
454 if *getU && vcsCmd.RemoteRepo != nil {
455 dir := filepath.Join(p.Internal.Build.SrcRoot, filepath.FromSlash(rootPath))
456 remote, err := vcsCmd.RemoteRepo(vcsCmd, dir)
457 if err != nil {
458
459
460 blindRepo = true
461 }
462 repo = remote
463 if !*getF && err == nil {
464 if rr, err := vcs.RepoRootForImportPath(importPrefix, vcs.IgnoreMod, security); err == nil {
465 repo := rr.Repo
466 if rr.VCS.ResolveRepo != nil {
467 resolved, err := rr.VCS.ResolveRepo(rr.VCS, dir, repo)
468 if err == nil {
469 repo = resolved
470 }
471 }
472 if remote != repo && rr.IsCustom {
473 return fmt.Errorf("%s is a custom import path for %s, but %s is checked out from %s", rr.Root, repo, dir, remote)
474 }
475 }
476 }
477 }
478 } else {
479
480
481 rr, err := vcs.RepoRootForImportPath(importPrefix, vcs.IgnoreMod, security)
482 if err != nil {
483 return err
484 }
485 vcsCmd, repo, rootPath = rr.VCS, rr.Repo, rr.Root
486 }
487 if !blindRepo && !vcsCmd.IsSecure(repo) && security != web.Insecure {
488 return fmt.Errorf("cannot download, %v uses insecure protocol", repo)
489 }
490
491 if p.Internal.Build.SrcRoot == "" {
492
493 list := filepath.SplitList(cfg.BuildContext.GOPATH)
494 if len(list) == 0 {
495 return fmt.Errorf("cannot download, $GOPATH not set. For more details see: 'go help gopath'")
496 }
497
498 if filepath.Clean(list[0]) == filepath.Clean(cfg.GOROOT) {
499 return fmt.Errorf("cannot download, $GOPATH must not be set to $GOROOT. For more details see: 'go help gopath'")
500 }
501 if _, err := os.Stat(filepath.Join(list[0], "src/cmd/go/alldocs.go")); err == nil {
502 return fmt.Errorf("cannot download, %s is a GOROOT, not a GOPATH. For more details see: 'go help gopath'", list[0])
503 }
504 p.Internal.Build.Root = list[0]
505 p.Internal.Build.SrcRoot = filepath.Join(list[0], "src")
506 p.Internal.Build.PkgRoot = filepath.Join(list[0], "pkg")
507 }
508 root := filepath.Join(p.Internal.Build.SrcRoot, filepath.FromSlash(rootPath))
509
510 if err := vcs.CheckNested(vcsCmd, root, p.Internal.Build.SrcRoot); err != nil {
511 return err
512 }
513
514
515 if downloadRootCache[root] {
516 return nil
517 }
518 downloadRootCache[root] = true
519
520 if cfg.BuildV {
521 fmt.Fprintf(os.Stderr, "%s (download)\n", rootPath)
522 }
523
524
525
526 meta := filepath.Join(root, "."+vcsCmd.Cmd)
527 if _, err := os.Stat(meta); err != nil {
528
529
530
531 if _, err := os.Stat(root); err == nil {
532 return fmt.Errorf("%s exists but %s does not - stale checkout?", root, meta)
533 }
534
535 _, err := os.Stat(p.Internal.Build.Root)
536 gopathExisted := err == nil
537
538
539 parent, _ := filepath.Split(root)
540 if err = os.MkdirAll(parent, 0777); err != nil {
541 return err
542 }
543 if cfg.BuildV && !gopathExisted && p.Internal.Build.Root == cfg.BuildContext.GOPATH {
544 fmt.Fprintf(os.Stderr, "created GOPATH=%s; see 'go help gopath'\n", p.Internal.Build.Root)
545 }
546
547 if err = vcsCmd.Create(root, repo); err != nil {
548 return err
549 }
550 } else {
551
552 if err = vcsCmd.Download(root); err != nil {
553 return err
554 }
555 }
556
557 if cfg.BuildN {
558
559
560
561 fmt.Fprintf(os.Stderr, "# cd %s; %s sync/update\n", root, vcsCmd.Cmd)
562 return nil
563 }
564
565
566 tags, err := vcsCmd.Tags(root)
567 if err != nil {
568 return err
569 }
570 vers := runtime.Version()
571 if i := strings.Index(vers, " "); i >= 0 {
572 vers = vers[:i]
573 }
574 if err := vcsCmd.TagSync(root, selectTag(vers, tags)); err != nil {
575 return err
576 }
577
578 return nil
579 }
580
581
582
583
584
585
586
587
588
589 func selectTag(goVersion string, tags []string) (match string) {
590 for _, t := range tags {
591 if t == "go1" {
592 return "go1"
593 }
594 }
595 return ""
596 }
597
598
599
600
601 func checkImportPath(path string) error {
602 if err := module.CheckImportPath(path); err != nil {
603 return err
604 }
605 checkElem := func(elem string) error {
606 if elem[0] == '.' {
607 return fmt.Errorf("malformed import path %q: leading dot in path element", path)
608 }
609 return nil
610 }
611 elemStart := 0
612 for i, r := range path {
613 if r == '/' {
614 if err := checkElem(path[elemStart:]); err != nil {
615 return err
616 }
617 elemStart = i + 1
618 }
619 }
620 if err := checkElem(path[elemStart:]); err != nil {
621 return err
622 }
623 return nil
624 }
625
View as plain text