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: modules not implemented")
118 }
119
120 work.BuildInit()
121
122 if *getF && !*getU {
123 base.Fatalf("go: cannot use -f flag without -u")
124 }
125 if *getInsecure {
126 base.Fatalf("go: -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: %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: %s exists as a file, but 'go get' requires package arguments", arg)
222 }
223 }
224 }
225 base.ExitIfErrors()
226
227 var pkgs []string
228 noModRoots := []string{}
229 for _, m := range search.ImportPathsQuiet(patterns, noModRoots) {
230 if len(m.Pkgs) == 0 && strings.Contains(m.Pattern(), "...") {
231 pkgs = append(pkgs, m.Pattern())
232 } else {
233 pkgs = append(pkgs, m.Pkgs...)
234 }
235 }
236 return pkgs
237 }
238
239
240
241
242
243 var downloadCache = map[string]bool{}
244
245
246
247
248
249
250 var downloadRootCache = map[string]bool{}
251
252
253
254 func download(arg string, parent *load.Package, stk *load.ImportStack, mode int) {
255 if mode&load.ResolveImport != 0 {
256
257 panic("internal error: download mode has useVendor set")
258 }
259 load1 := func(path string, mode int) *load.Package {
260 if parent == nil {
261 mode := 0
262 return load.LoadImport(context.TODO(), load.PackageOpts{}, path, base.Cwd(), nil, stk, nil, mode)
263 }
264 return load.LoadImport(context.TODO(), load.PackageOpts{}, path, parent.Dir, parent, stk, nil, mode|load.ResolveModule)
265 }
266
267 p := load1(arg, mode)
268 if p.Error != nil && p.Error.Hard {
269 base.Errorf("%s", p.Error)
270 return
271 }
272
273
274
275
276
277
278
279
280
281 arg = p.ImportPath
282
283
284 if p.Standard {
285 return
286 }
287
288
289
290
291 if downloadCache[arg] && mode&load.GetTestDeps == 0 {
292 return
293 }
294 downloadCache[arg] = true
295
296 pkgs := []*load.Package{p}
297 wildcardOkay := len(*stk) == 0
298 isWildcard := false
299
300
301 if p.Dir == "" || *getU {
302
303 stk.Push(arg)
304 err := downloadPackage(p)
305 if err != nil {
306 base.Errorf("%s", &load.PackageError{ImportStack: stk.Copy(), Err: err})
307 stk.Pop()
308 return
309 }
310 stk.Pop()
311
312 args := []string{arg}
313
314
315
316 if wildcardOkay && strings.Contains(arg, "...") {
317 match := search.NewMatch(arg)
318 if match.IsLocal() {
319 noModRoots := []string{}
320 match.MatchDirs(noModRoots)
321 args = match.Dirs
322 } else {
323 match.MatchPackages()
324 args = match.Pkgs
325 }
326 for _, err := range match.Errs {
327 base.Errorf("%s", err)
328 }
329 isWildcard = true
330 }
331
332
333
334 load.ClearPackageCachePartial(args)
335
336 pkgs = pkgs[:0]
337 for _, arg := range args {
338
339
340
341 p := load1(arg, mode)
342 if p.Error != nil {
343 base.Errorf("%s", p.Error)
344 continue
345 }
346 pkgs = append(pkgs, p)
347 }
348 }
349
350
351
352 for _, p := range pkgs {
353 if *getFix {
354 files := base.RelPaths(p.InternalAllGoFiles())
355 base.Run(cfg.BuildToolexec, str.StringList(base.Tool("fix"), files))
356
357
358 p = load.ReloadPackageNoFlags(arg, stk)
359 if p.Error != nil {
360 base.Errorf("%s", p.Error)
361 return
362 }
363 }
364
365 if isWildcard {
366
367
368 stk.Push(p.ImportPath)
369 }
370
371
372 imports := p.Imports
373 if mode&load.GetTestDeps != 0 {
374
375
376
377 imports = str.StringList(imports, p.TestImports, p.XTestImports)
378 }
379 for i, path := range imports {
380 if path == "C" {
381 continue
382 }
383
384
385
386 orig := path
387 if i < len(p.Internal.Build.Imports) {
388 orig = p.Internal.Build.Imports[i]
389 }
390 if j, ok := load.FindVendor(orig); ok {
391 stk.Push(path)
392 err := &load.PackageError{
393 ImportStack: stk.Copy(),
394 Err: load.ImportErrorf(path, "%s must be imported as %s", path, path[j+len("vendor/"):]),
395 }
396 stk.Pop()
397 base.Errorf("%s", err)
398 continue
399 }
400
401
402
403
404 if i >= len(p.Imports) {
405 path = load.ResolveImportPath(p, path)
406 }
407 download(path, p, stk, 0)
408 }
409
410 if isWildcard {
411 stk.Pop()
412 }
413 }
414 }
415
416
417
418 func downloadPackage(p *load.Package) error {
419 var (
420 vcsCmd *vcs.Cmd
421 repo, rootPath, repoDir string
422 err error
423 blindRepo bool
424 )
425
426
427
428
429
430
431 importPrefix := p.ImportPath
432 if i := strings.Index(importPrefix, "..."); i >= 0 {
433 slash := strings.LastIndexByte(importPrefix[:i], '/')
434 if slash < 0 {
435 return fmt.Errorf("cannot expand ... in %q", p.ImportPath)
436 }
437 importPrefix = importPrefix[:slash]
438 }
439 if err := checkImportPath(importPrefix); err != nil {
440 return fmt.Errorf("%s: invalid import path: %v", p.ImportPath, err)
441 }
442 security := web.SecureOnly
443 if module.MatchPrefixPatterns(cfg.GOINSECURE, importPrefix) {
444 security = web.Insecure
445 }
446
447 if p.Internal.Build.SrcRoot != "" {
448
449 const allowNesting = false
450 repoDir, vcsCmd, err = vcs.FromDir(p.Dir, p.Internal.Build.SrcRoot, allowNesting)
451 if err != nil {
452 return err
453 }
454 if !str.HasFilePathPrefix(repoDir, p.Internal.Build.SrcRoot) {
455 panic(fmt.Sprintf("repository %q not in source root %q", repo, p.Internal.Build.SrcRoot))
456 }
457 rootPath = str.TrimFilePathPrefix(repoDir, p.Internal.Build.SrcRoot)
458 if err := vcs.CheckGOVCS(vcsCmd, rootPath); err != nil {
459 return err
460 }
461
462 repo = "<local>"
463
464
465 if *getU && vcsCmd.RemoteRepo != nil {
466 dir := filepath.Join(p.Internal.Build.SrcRoot, filepath.FromSlash(rootPath))
467 remote, err := vcsCmd.RemoteRepo(vcsCmd, dir)
468 if err != nil {
469
470
471 blindRepo = true
472 }
473 repo = remote
474 if !*getF && err == nil {
475 if rr, err := vcs.RepoRootForImportPath(importPrefix, vcs.IgnoreMod, security); err == nil {
476 repo := rr.Repo
477 if rr.VCS.ResolveRepo != nil {
478 resolved, err := rr.VCS.ResolveRepo(rr.VCS, dir, repo)
479 if err == nil {
480 repo = resolved
481 }
482 }
483 if remote != repo && rr.IsCustom {
484 return fmt.Errorf("%s is a custom import path for %s, but %s is checked out from %s", rr.Root, repo, dir, remote)
485 }
486 }
487 }
488 }
489 } else {
490
491
492 rr, err := vcs.RepoRootForImportPath(importPrefix, vcs.IgnoreMod, security)
493 if err != nil {
494 return err
495 }
496 vcsCmd, repo, rootPath = rr.VCS, rr.Repo, rr.Root
497 }
498 if !blindRepo && !vcsCmd.IsSecure(repo) && security != web.Insecure {
499 return fmt.Errorf("cannot download, %v uses insecure protocol", repo)
500 }
501
502 if p.Internal.Build.SrcRoot == "" {
503
504 list := filepath.SplitList(cfg.BuildContext.GOPATH)
505 if len(list) == 0 {
506 return fmt.Errorf("cannot download, $GOPATH not set. For more details see: 'go help gopath'")
507 }
508
509 if filepath.Clean(list[0]) == filepath.Clean(cfg.GOROOT) {
510 return fmt.Errorf("cannot download, $GOPATH must not be set to $GOROOT. For more details see: 'go help gopath'")
511 }
512 if _, err := os.Stat(filepath.Join(list[0], "src/cmd/go/alldocs.go")); err == nil {
513 return fmt.Errorf("cannot download, %s is a GOROOT, not a GOPATH. For more details see: 'go help gopath'", list[0])
514 }
515 p.Internal.Build.Root = list[0]
516 p.Internal.Build.SrcRoot = filepath.Join(list[0], "src")
517 p.Internal.Build.PkgRoot = filepath.Join(list[0], "pkg")
518 }
519 root := filepath.Join(p.Internal.Build.SrcRoot, filepath.FromSlash(rootPath))
520
521 if err := vcs.CheckNested(vcsCmd, root, p.Internal.Build.SrcRoot); err != nil {
522 return err
523 }
524
525
526 if downloadRootCache[root] {
527 return nil
528 }
529 downloadRootCache[root] = true
530
531 if cfg.BuildV {
532 fmt.Fprintf(os.Stderr, "%s (download)\n", rootPath)
533 }
534
535
536
537 meta := filepath.Join(root, "."+vcsCmd.Cmd)
538 if _, err := os.Stat(meta); err != nil {
539
540
541
542 if _, err := os.Stat(root); err == nil {
543 return fmt.Errorf("%s exists but %s does not - stale checkout?", root, meta)
544 }
545
546 _, err := os.Stat(p.Internal.Build.Root)
547 gopathExisted := err == nil
548
549
550 parent, _ := filepath.Split(root)
551 if err = os.MkdirAll(parent, 0777); err != nil {
552 return err
553 }
554 if cfg.BuildV && !gopathExisted && p.Internal.Build.Root == cfg.BuildContext.GOPATH {
555 fmt.Fprintf(os.Stderr, "created GOPATH=%s; see 'go help gopath'\n", p.Internal.Build.Root)
556 }
557
558 if err = vcsCmd.Create(root, repo); err != nil {
559 return err
560 }
561 } else {
562
563 if err = vcsCmd.Download(root); err != nil {
564 return err
565 }
566 }
567
568 if cfg.BuildN {
569
570
571
572 fmt.Fprintf(os.Stderr, "# cd %s; %s sync/update\n", root, vcsCmd.Cmd)
573 return nil
574 }
575
576
577 tags, err := vcsCmd.Tags(root)
578 if err != nil {
579 return err
580 }
581 vers := runtime.Version()
582 if i := strings.Index(vers, " "); i >= 0 {
583 vers = vers[:i]
584 }
585 if err := vcsCmd.TagSync(root, selectTag(vers, tags)); err != nil {
586 return err
587 }
588
589 return nil
590 }
591
592
593
594
595
596
597
598
599
600 func selectTag(goVersion string, tags []string) (match string) {
601 for _, t := range tags {
602 if t == "go1" {
603 return "go1"
604 }
605 }
606 return ""
607 }
608
609
610
611
612 func checkImportPath(path string) error {
613 if err := module.CheckImportPath(path); err != nil {
614 return err
615 }
616 checkElem := func(elem string) error {
617 if elem[0] == '.' {
618 return fmt.Errorf("malformed import path %q: leading dot in path element", path)
619 }
620 return nil
621 }
622 elemStart := 0
623 for i, r := range path {
624 if r == '/' {
625 if err := checkElem(path[elemStart:]); err != nil {
626 return err
627 }
628 elemStart = i + 1
629 }
630 }
631 if err := checkElem(path[elemStart:]); err != nil {
632 return err
633 }
634 return nil
635 }
636
View as plain text