github.com/zxy12/go_duplicate_112_new@v0.0.0-20200807091221-747231827200/src/cmd/go/internal/modload/init.go (about) 1 // Copyright 2018 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 modload 6 7 import ( 8 "bytes" 9 "cmd/go/internal/base" 10 "cmd/go/internal/cache" 11 "cmd/go/internal/cfg" 12 "cmd/go/internal/load" 13 "cmd/go/internal/modconv" 14 "cmd/go/internal/modfetch" 15 "cmd/go/internal/modfetch/codehost" 16 "cmd/go/internal/modfile" 17 "cmd/go/internal/module" 18 "cmd/go/internal/mvs" 19 "cmd/go/internal/renameio" 20 "cmd/go/internal/search" 21 "encoding/json" 22 "fmt" 23 "go/build" 24 "io/ioutil" 25 "os" 26 "path" 27 "path/filepath" 28 "regexp" 29 "runtime/debug" 30 "strconv" 31 "strings" 32 ) 33 34 var ( 35 cwd string // TODO(bcmills): Is this redundant with base.Cwd? 36 MustUseModules = mustUseModules() 37 initialized bool 38 39 modRoot string 40 modFile *modfile.File 41 modFileData []byte 42 excluded map[module.Version]bool 43 Target module.Version 44 45 gopath string 46 47 CmdModInit bool // running 'go mod init' 48 CmdModModule string // module argument for 'go mod init' 49 ) 50 51 // ModFile returns the parsed go.mod file. 52 // 53 // Note that after calling ImportPaths or LoadBuildList, 54 // the require statements in the modfile.File are no longer 55 // the source of truth and will be ignored: edits made directly 56 // will be lost at the next call to WriteGoMod. 57 // To make permanent changes to the require statements 58 // in go.mod, edit it before calling ImportPaths or LoadBuildList. 59 func ModFile() *modfile.File { 60 Init() 61 if modFile == nil { 62 die() 63 } 64 return modFile 65 } 66 67 func BinDir() string { 68 Init() 69 return filepath.Join(gopath, "bin") 70 } 71 72 // mustUseModules reports whether we are invoked as vgo 73 // (as opposed to go). 74 // If so, we only support builds with go.mod files. 75 func mustUseModules() bool { 76 name := os.Args[0] 77 name = name[strings.LastIndex(name, "/")+1:] 78 name = name[strings.LastIndex(name, `\`)+1:] 79 return strings.HasPrefix(name, "vgo") 80 } 81 82 var inGOPATH bool // running in GOPATH/src 83 84 // Init determines whether module mode is enabled, locates the root of the 85 // current module (if any), sets environment variables for Git subprocesses, and 86 // configures the cfg, codehost, load, modfetch, and search packages for use 87 // with modules. 88 func Init() { 89 if initialized { 90 return 91 } 92 initialized = true 93 94 env := os.Getenv("GO111MODULE") 95 switch env { 96 default: 97 base.Fatalf("go: unknown environment setting GO111MODULE=%s", env) 98 case "", "auto": 99 // leave MustUseModules alone 100 case "on": 101 MustUseModules = true 102 case "off": 103 if !MustUseModules { 104 return 105 } 106 } 107 108 // Disable any prompting for passwords by Git. 109 // Only has an effect for 2.3.0 or later, but avoiding 110 // the prompt in earlier versions is just too hard. 111 // If user has explicitly set GIT_TERMINAL_PROMPT=1, keep 112 // prompting. 113 // See golang.org/issue/9341 and golang.org/issue/12706. 114 if os.Getenv("GIT_TERMINAL_PROMPT") == "" { 115 os.Setenv("GIT_TERMINAL_PROMPT", "0") 116 } 117 118 // Disable any ssh connection pooling by Git. 119 // If a Git subprocess forks a child into the background to cache a new connection, 120 // that child keeps stdout/stderr open. After the Git subprocess exits, 121 // os /exec expects to be able to read from the stdout/stderr pipe 122 // until EOF to get all the data that the Git subprocess wrote before exiting. 123 // The EOF doesn't come until the child exits too, because the child 124 // is holding the write end of the pipe. 125 // This is unfortunate, but it has come up at least twice 126 // (see golang.org/issue/13453 and golang.org/issue/16104) 127 // and confuses users when it does. 128 // If the user has explicitly set GIT_SSH or GIT_SSH_COMMAND, 129 // assume they know what they are doing and don't step on it. 130 // But default to turning off ControlMaster. 131 if os.Getenv("GIT_SSH") == "" && os.Getenv("GIT_SSH_COMMAND") == "" { 132 os.Setenv("GIT_SSH_COMMAND", "ssh -o ControlMaster=no") 133 } 134 135 var err error 136 cwd, err = os.Getwd() 137 if err != nil { 138 base.Fatalf("go: %v", err) 139 } 140 141 inGOPATH = false 142 for _, gopath := range filepath.SplitList(cfg.BuildContext.GOPATH) { 143 if gopath == "" { 144 continue 145 } 146 if search.InDir(cwd, filepath.Join(gopath, "src")) != "" { 147 inGOPATH = true 148 break 149 } 150 } 151 152 if inGOPATH && !MustUseModules { 153 if CmdModInit { 154 die() // Don't init a module that we're just going to ignore. 155 } 156 // No automatic enabling in GOPATH. 157 if root, _ := FindModuleRoot(cwd, "", false); root != "" { 158 cfg.GoModInGOPATH = filepath.Join(root, "go.mod") 159 } 160 return 161 } 162 163 if CmdModInit { 164 // Running 'go mod init': go.mod will be created in current directory. 165 modRoot = cwd 166 } else { 167 modRoot, _ = FindModuleRoot(cwd, "", MustUseModules) 168 if modRoot == "" { 169 if !MustUseModules { 170 // GO111MODULE is 'auto' (or unset), and we can't find a module root. 171 // Stay in GOPATH mode. 172 return 173 } 174 } else if search.InDir(modRoot, os.TempDir()) == "." { 175 // If you create /tmp/go.mod for experimenting, 176 // then any tests that create work directories under /tmp 177 // will find it and get modules when they're not expecting them. 178 // It's a bit of a peculiar thing to disallow but quite mysterious 179 // when it happens. See golang.org/issue/26708. 180 modRoot = "" 181 fmt.Fprintf(os.Stderr, "go: warning: ignoring go.mod in system temp root %v\n", os.TempDir()) 182 } 183 } 184 185 // We're in module mode. Install the hooks to make it work. 186 187 if c := cache.Default(); c == nil { 188 // With modules, there are no install locations for packages 189 // other than the build cache. 190 base.Fatalf("go: cannot use modules with build cache disabled") 191 } 192 193 list := filepath.SplitList(cfg.BuildContext.GOPATH) 194 if len(list) == 0 || list[0] == "" { 195 base.Fatalf("missing $GOPATH") 196 } 197 gopath = list[0] 198 if _, err := os.Stat(filepath.Join(gopath, "go.mod")); err == nil { 199 base.Fatalf("$GOPATH/go.mod exists but should not") 200 } 201 202 oldSrcMod := filepath.Join(list[0], "src/mod") 203 pkgMod := filepath.Join(list[0], "pkg/mod") 204 infoOld, errOld := os.Stat(oldSrcMod) 205 _, errMod := os.Stat(pkgMod) 206 if errOld == nil && infoOld.IsDir() && errMod != nil && os.IsNotExist(errMod) { 207 os.Rename(oldSrcMod, pkgMod) 208 } 209 210 modfetch.PkgMod = pkgMod 211 codehost.WorkRoot = filepath.Join(pkgMod, "cache/vcs") 212 213 cfg.ModulesEnabled = true 214 load.ModBinDir = BinDir 215 load.ModLookup = Lookup 216 load.ModPackageModuleInfo = PackageModuleInfo 217 load.ModImportPaths = ImportPaths 218 load.ModPackageBuildInfo = PackageBuildInfo 219 load.ModInfoProg = ModInfoProg 220 load.ModImportFromFiles = ImportFromFiles 221 load.ModDirImportPath = DirImportPath 222 223 if modRoot == "" { 224 // We're in module mode, but not inside a module. 225 // 226 // If the command is 'go get' or 'go list' and all of the args are in the 227 // same existing module, we could use that module's download directory in 228 // the module cache as the module root, applying any replacements and/or 229 // exclusions specified by that module. However, that would leave us in a 230 // strange state: we want 'go get' to be consistent with 'go list', and 'go 231 // list' should be able to operate on multiple modules. Moreover, the 'get' 232 // target might specify relative file paths (e.g. in the same repository) as 233 // replacements, and we would not be able to apply those anyway: we would 234 // need to either error out or ignore just those replacements, when a build 235 // from an empty module could proceed without error. 236 // 237 // Instead, we'll operate as though we're in some ephemeral external module, 238 // ignoring all replacements and exclusions uniformly. 239 240 // Normally we check sums using the go.sum file from the main module, but 241 // without a main module we do not have an authoritative go.sum file. 242 // 243 // TODO(bcmills): In Go 1.13, check sums when outside the main module. 244 // 245 // One possible approach is to merge the go.sum files from all of the 246 // modules we download: that doesn't protect us against bad top-level 247 // modules, but it at least ensures consistency for transitive dependencies. 248 } else { 249 modfetch.GoSumFile = filepath.Join(modRoot, "go.sum") 250 search.SetModRoot(modRoot) 251 } 252 } 253 254 func init() { 255 load.ModInit = Init 256 257 // Set modfetch.PkgMod unconditionally, so that go clean -modcache can run even without modules enabled. 258 if list := filepath.SplitList(cfg.BuildContext.GOPATH); len(list) > 0 && list[0] != "" { 259 modfetch.PkgMod = filepath.Join(list[0], "pkg/mod") 260 } 261 } 262 263 // Enabled reports whether modules are (or must be) enabled. 264 // If modules are enabled but there is no main module, Enabled returns true 265 // and then the first use of module information will call die 266 // (usually through MustModRoot). 267 func Enabled() bool { 268 Init() 269 return modRoot != "" || MustUseModules 270 } 271 272 // ModRoot returns the root of the main module. 273 // It calls base.Fatalf if there is no main module. 274 func ModRoot() string { 275 if !HasModRoot() { 276 die() 277 } 278 return modRoot 279 } 280 281 // HasModRoot reports whether a main module is present. 282 // HasModRoot may return false even if Enabled returns true: for example, 'get' 283 // does not require a main module. 284 func HasModRoot() bool { 285 Init() 286 return modRoot != "" 287 } 288 289 // printStackInDie causes die to print a stack trace. 290 // 291 // It is enabled by the testgo tag, and helps to diagnose paths that 292 // unexpectedly require a main module. 293 var printStackInDie = false 294 295 func die() { 296 if printStackInDie { 297 debug.PrintStack() 298 } 299 if os.Getenv("GO111MODULE") == "off" { 300 base.Fatalf("go: modules disabled by GO111MODULE=off; see 'go help modules'") 301 } 302 if inGOPATH && !MustUseModules { 303 base.Fatalf("go: modules disabled inside GOPATH/src by GO111MODULE=auto; see 'go help modules'") 304 } 305 base.Fatalf("go: cannot find main module; see 'go help modules'") 306 } 307 308 // InitMod sets Target and, if there is a main module, parses the initial build 309 // list from its go.mod file, creating and populating that file if needed. 310 func InitMod() { 311 if len(buildList) > 0 { 312 return 313 } 314 315 Init() 316 if modRoot == "" { 317 Target = module.Version{Path: "command-line-arguments"} 318 buildList = []module.Version{Target} 319 return 320 } 321 322 if CmdModInit { 323 // Running go mod init: do legacy module conversion 324 legacyModInit() 325 modFileToBuildList() 326 WriteGoMod() 327 return 328 } 329 330 gomod := filepath.Join(modRoot, "go.mod") 331 data, err := ioutil.ReadFile(gomod) 332 if err != nil { 333 if os.IsNotExist(err) { 334 legacyModInit() 335 modFileToBuildList() 336 WriteGoMod() 337 return 338 } 339 base.Fatalf("go: %v", err) 340 } 341 342 f, err := modfile.Parse(gomod, data, fixVersion) 343 if err != nil { 344 // Errors returned by modfile.Parse begin with file:line. 345 base.Fatalf("go: errors parsing go.mod:\n%s\n", err) 346 } 347 modFile = f 348 modFileData = data 349 350 if len(f.Syntax.Stmt) == 0 || f.Module == nil { 351 // Empty mod file. Must add module path. 352 path, err := FindModulePath(modRoot) 353 if err != nil { 354 base.Fatalf("go: %v", err) 355 } 356 f.AddModuleStmt(path) 357 } 358 359 if len(f.Syntax.Stmt) == 1 && f.Module != nil { 360 // Entire file is just a module statement. 361 // Populate require if possible. 362 legacyModInit() 363 } 364 365 excluded = make(map[module.Version]bool) 366 for _, x := range f.Exclude { 367 excluded[x.Mod] = true 368 } 369 modFileToBuildList() 370 WriteGoMod() 371 } 372 373 // modFileToBuildList initializes buildList from the modFile. 374 func modFileToBuildList() { 375 Target = modFile.Module.Mod 376 list := []module.Version{Target} 377 for _, r := range modFile.Require { 378 list = append(list, r.Mod) 379 } 380 buildList = list 381 } 382 383 // Allowed reports whether module m is allowed (not excluded) by the main module's go.mod. 384 func Allowed(m module.Version) bool { 385 return !excluded[m] 386 } 387 388 func legacyModInit() { 389 if modFile == nil { 390 path, err := FindModulePath(modRoot) 391 if err != nil { 392 base.Fatalf("go: %v", err) 393 } 394 fmt.Fprintf(os.Stderr, "go: creating new go.mod: module %s\n", path) 395 modFile = new(modfile.File) 396 modFile.AddModuleStmt(path) 397 } 398 399 addGoStmt() 400 401 for _, name := range altConfigs { 402 cfg := filepath.Join(modRoot, name) 403 data, err := ioutil.ReadFile(cfg) 404 if err == nil { 405 convert := modconv.Converters[name] 406 if convert == nil { 407 return 408 } 409 fmt.Fprintf(os.Stderr, "go: copying requirements from %s\n", base.ShortPath(cfg)) 410 cfg = filepath.ToSlash(cfg) 411 if err := modconv.ConvertLegacyConfig(modFile, cfg, data); err != nil { 412 base.Fatalf("go: %v", err) 413 } 414 if len(modFile.Syntax.Stmt) == 1 { 415 // Add comment to avoid re-converting every time it runs. 416 modFile.AddComment("// go: no requirements found in " + name) 417 } 418 return 419 } 420 } 421 } 422 423 // InitGoStmt adds a go statement, unless there already is one. 424 func InitGoStmt() { 425 if modFile.Go == nil { 426 addGoStmt() 427 } 428 } 429 430 // addGoStmt adds a go statement referring to the current version. 431 func addGoStmt() { 432 tags := build.Default.ReleaseTags 433 version := tags[len(tags)-1] 434 if !strings.HasPrefix(version, "go") || !modfile.GoVersionRE.MatchString(version[2:]) { 435 base.Fatalf("go: unrecognized default version %q", version) 436 } 437 if err := modFile.AddGoStmt(version[2:]); err != nil { 438 base.Fatalf("go: internal error: %v", err) 439 } 440 } 441 442 var altConfigs = []string{ 443 "Gopkg.lock", 444 445 "GLOCKFILE", 446 "Godeps/Godeps.json", 447 "dependencies.tsv", 448 "glide.lock", 449 "vendor.conf", 450 "vendor.yml", 451 "vendor/manifest", 452 "vendor/vendor.json", 453 454 ".git/config", 455 } 456 457 // Exported only for testing. 458 func FindModuleRoot(dir, limit string, legacyConfigOK bool) (root, file string) { 459 dir = filepath.Clean(dir) 460 dir1 := dir 461 limit = filepath.Clean(limit) 462 463 // Look for enclosing go.mod. 464 for { 465 if fi, err := os.Stat(filepath.Join(dir, "go.mod")); err == nil && !fi.IsDir() { 466 return dir, "go.mod" 467 } 468 if dir == limit { 469 break 470 } 471 d := filepath.Dir(dir) 472 if d == dir { 473 break 474 } 475 dir = d 476 } 477 478 // Failing that, look for enclosing alternate version config. 479 if legacyConfigOK { 480 dir = dir1 481 for { 482 for _, name := range altConfigs { 483 if fi, err := os.Stat(filepath.Join(dir, name)); err == nil && !fi.IsDir() { 484 return dir, name 485 } 486 } 487 if dir == limit { 488 break 489 } 490 d := filepath.Dir(dir) 491 if d == dir { 492 break 493 } 494 dir = d 495 } 496 } 497 498 return "", "" 499 } 500 501 // Exported only for testing. 502 func FindModulePath(dir string) (string, error) { 503 if CmdModModule != "" { 504 // Running go mod init x/y/z; return x/y/z. 505 return CmdModModule, nil 506 } 507 508 // Cast about for import comments, 509 // first in top-level directory, then in subdirectories. 510 list, _ := ioutil.ReadDir(dir) 511 for _, info := range list { 512 if info.Mode().IsRegular() && strings.HasSuffix(info.Name(), ".go") { 513 if com := findImportComment(filepath.Join(dir, info.Name())); com != "" { 514 return com, nil 515 } 516 } 517 } 518 for _, info1 := range list { 519 if info1.IsDir() { 520 files, _ := ioutil.ReadDir(filepath.Join(dir, info1.Name())) 521 for _, info2 := range files { 522 if info2.Mode().IsRegular() && strings.HasSuffix(info2.Name(), ".go") { 523 if com := findImportComment(filepath.Join(dir, info1.Name(), info2.Name())); com != "" { 524 return path.Dir(com), nil 525 } 526 } 527 } 528 } 529 } 530 531 // Look for Godeps.json declaring import path. 532 data, _ := ioutil.ReadFile(filepath.Join(dir, "Godeps/Godeps.json")) 533 var cfg1 struct{ ImportPath string } 534 json.Unmarshal(data, &cfg1) 535 if cfg1.ImportPath != "" { 536 return cfg1.ImportPath, nil 537 } 538 539 // Look for vendor.json declaring import path. 540 data, _ = ioutil.ReadFile(filepath.Join(dir, "vendor/vendor.json")) 541 var cfg2 struct{ RootPath string } 542 json.Unmarshal(data, &cfg2) 543 if cfg2.RootPath != "" { 544 return cfg2.RootPath, nil 545 } 546 547 // Look for path in GOPATH. 548 for _, gpdir := range filepath.SplitList(cfg.BuildContext.GOPATH) { 549 if gpdir == "" { 550 continue 551 } 552 if rel := search.InDir(dir, filepath.Join(gpdir, "src")); rel != "" && rel != "." { 553 return filepath.ToSlash(rel), nil 554 } 555 } 556 557 // Look for .git/config with github origin as last resort. 558 data, _ = ioutil.ReadFile(filepath.Join(dir, ".git/config")) 559 if m := gitOriginRE.FindSubmatch(data); m != nil { 560 return "github.com/" + string(m[1]), nil 561 } 562 563 return "", fmt.Errorf("cannot determine module path for source directory %s (outside GOPATH, no import comments)", dir) 564 } 565 566 var ( 567 gitOriginRE = regexp.MustCompile(`(?m)^\[remote "origin"\]\r?\n\turl = (?:https://github.com/|git@github.com:|gh:)([^/]+/[^/]+?)(\.git)?\r?\n`) 568 importCommentRE = regexp.MustCompile(`(?m)^package[ \t]+[^ \t\r\n/]+[ \t]+//[ \t]+import[ \t]+(\"[^"]+\")[ \t]*\r?\n`) 569 ) 570 571 func findImportComment(file string) string { 572 data, err := ioutil.ReadFile(file) 573 if err != nil { 574 return "" 575 } 576 m := importCommentRE.FindSubmatch(data) 577 if m == nil { 578 return "" 579 } 580 path, err := strconv.Unquote(string(m[1])) 581 if err != nil { 582 return "" 583 } 584 return path 585 } 586 587 var allowWriteGoMod = true 588 589 // DisallowWriteGoMod causes future calls to WriteGoMod to do nothing at all. 590 func DisallowWriteGoMod() { 591 allowWriteGoMod = false 592 } 593 594 // AllowWriteGoMod undoes the effect of DisallowWriteGoMod: 595 // future calls to WriteGoMod will update go.mod if needed. 596 // Note that any past calls have been discarded, so typically 597 // a call to AlowWriteGoMod should be followed by a call to WriteGoMod. 598 func AllowWriteGoMod() { 599 allowWriteGoMod = true 600 } 601 602 // MinReqs returns a Reqs with minimal dependencies of Target, 603 // as will be written to go.mod. 604 func MinReqs() mvs.Reqs { 605 var direct []string 606 for _, m := range buildList[1:] { 607 if loaded.direct[m.Path] { 608 direct = append(direct, m.Path) 609 } 610 } 611 min, err := mvs.Req(Target, buildList, direct, Reqs()) 612 if err != nil { 613 base.Fatalf("go: %v", err) 614 } 615 return &mvsReqs{buildList: append([]module.Version{Target}, min...)} 616 } 617 618 // WriteGoMod writes the current build list back to go.mod. 619 func WriteGoMod() { 620 // If we're using -mod=vendor we basically ignored 621 // go.mod, so definitely don't try to write back our 622 // incomplete view of the world. 623 if !allowWriteGoMod || cfg.BuildMod == "vendor" { 624 return 625 } 626 627 // If we aren't in a module, we don't have anywhere to write a go.mod file. 628 if modRoot == "" { 629 return 630 } 631 632 if loaded != nil { 633 reqs := MinReqs() 634 min, err := reqs.Required(Target) 635 if err != nil { 636 base.Fatalf("go: %v", err) 637 } 638 var list []*modfile.Require 639 for _, m := range min { 640 list = append(list, &modfile.Require{ 641 Mod: m, 642 Indirect: !loaded.direct[m.Path], 643 }) 644 } 645 modFile.SetRequire(list) 646 } 647 648 modFile.Cleanup() // clean file after edits 649 new, err := modFile.Format() 650 if err != nil { 651 base.Fatalf("go: %v", err) 652 } 653 654 // Always update go.sum, even if we didn't change go.mod: we may have 655 // downloaded modules that we didn't have before. 656 modfetch.WriteGoSum() 657 658 if bytes.Equal(new, modFileData) { 659 // We don't need to modify go.mod from what we read previously. 660 // Ignore any intervening edits. 661 return 662 } 663 if cfg.BuildMod == "readonly" { 664 base.Fatalf("go: updates to go.mod needed, disabled by -mod=readonly") 665 } 666 667 unlock := modfetch.SideLock() 668 defer unlock() 669 670 file := filepath.Join(modRoot, "go.mod") 671 old, err := ioutil.ReadFile(file) 672 if !bytes.Equal(old, modFileData) { 673 if bytes.Equal(old, new) { 674 // Some other process wrote the same go.mod file that we were about to write. 675 modFileData = new 676 return 677 } 678 if err != nil { 679 base.Fatalf("go: can't determine whether go.mod has changed: %v", err) 680 } 681 // The contents of the go.mod file have changed. In theory we could add all 682 // of the new modules to the build list, recompute, and check whether any 683 // module in *our* build list got bumped to a different version, but that's 684 // a lot of work for marginal benefit. Instead, fail the command: if users 685 // want to run concurrent commands, they need to start with a complete, 686 // consistent module definition. 687 base.Fatalf("go: updates to go.mod needed, but contents have changed") 688 689 } 690 691 if err := renameio.WriteFile(file, new); err != nil { 692 base.Fatalf("error writing go.mod: %v", err) 693 } 694 modFileData = new 695 } 696 697 func fixVersion(path, vers string) (string, error) { 698 // Special case: remove the old -gopkgin- hack. 699 if strings.HasPrefix(path, "gopkg.in/") && strings.Contains(vers, "-gopkgin-") { 700 vers = vers[strings.Index(vers, "-gopkgin-")+len("-gopkgin-"):] 701 } 702 703 // fixVersion is called speculatively on every 704 // module, version pair from every go.mod file. 705 // Avoid the query if it looks OK. 706 _, pathMajor, ok := module.SplitPathVersion(path) 707 if !ok { 708 return "", fmt.Errorf("malformed module path: %s", path) 709 } 710 if vers != "" && module.CanonicalVersion(vers) == vers && module.MatchPathMajor(vers, pathMajor) { 711 return vers, nil 712 } 713 714 info, err := Query(path, vers, nil) 715 if err != nil { 716 return "", err 717 } 718 return info.Version, nil 719 }