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.
10 "cmd/go/internal/cache"
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"
19 "cmd/go/internal/search"
33 MustUseModules
= mustUseModules()
38 excluded
map[module
.Version
]bool
43 CmdModInit
bool // running 'go mod init'
44 CmdModModule
string // module argument for 'go mod init'
47 // ModFile returns the parsed go.mod file.
49 // Note that after calling ImportPaths or LoadBuildList,
50 // the require statements in the modfile.File are no longer
51 // the source of truth and will be ignored: edits made directly
52 // will be lost at the next call to WriteGoMod.
53 // To make permanent changes to the require statements
54 // in go.mod, edit it before calling ImportPaths or LoadBuildList.
55 func ModFile() *modfile
.File
{
59 func BinDir() string {
61 return filepath
.Join(gopath
, "bin")
64 // mustUseModules reports whether we are invoked as vgo
65 // (as opposed to go).
66 // If so, we only support builds with go.mod files.
67 func mustUseModules() bool {
69 name
= name
[strings
.LastIndex(name
, "/")+1:]
70 name
= name
[strings
.LastIndex(name
, `\`)+1:]
71 return strings
.HasPrefix(name
, "vgo")
74 var inGOPATH
bool // running in GOPATH/src
82 env
:= os
.Getenv("GO111MODULE")
85 base
.Fatalf("go: unknown environment setting GO111MODULE=%s", env
)
87 // leave MustUseModules alone
96 // Disable any prompting for passwords by Git.
97 // Only has an effect for 2.3.0 or later, but avoiding
98 // the prompt in earlier versions is just too hard.
99 // If user has explicitly set GIT_TERMINAL_PROMPT=1, keep
101 // See golang.org/issue/9341 and golang.org/issue/12706.
102 if os
.Getenv("GIT_TERMINAL_PROMPT") == "" {
103 os
.Setenv("GIT_TERMINAL_PROMPT", "0")
106 // Disable any ssh connection pooling by Git.
107 // If a Git subprocess forks a child into the background to cache a new connection,
108 // that child keeps stdout/stderr open. After the Git subprocess exits,
109 // os /exec expects to be able to read from the stdout/stderr pipe
110 // until EOF to get all the data that the Git subprocess wrote before exiting.
111 // The EOF doesn't come until the child exits too, because the child
112 // is holding the write end of the pipe.
113 // This is unfortunate, but it has come up at least twice
114 // (see golang.org/issue/13453 and golang.org/issue/16104)
115 // and confuses users when it does.
116 // If the user has explicitly set GIT_SSH or GIT_SSH_COMMAND,
117 // assume they know what they are doing and don't step on it.
118 // But default to turning off ControlMaster.
119 if os
.Getenv("GIT_SSH") == "" && os
.Getenv("GIT_SSH_COMMAND") == "" {
120 os
.Setenv("GIT_SSH_COMMAND", "ssh -o ControlMaster=no")
124 cwd
, err
= os
.Getwd()
126 base
.Fatalf("go: %v", err
)
130 for _
, gopath
:= range filepath
.SplitList(cfg
.BuildContext
.GOPATH
) {
134 if search
.InDir(cwd
, filepath
.Join(gopath
, "src")) != "" {
140 if inGOPATH
&& !MustUseModules
{
141 // No automatic enabling in GOPATH.
142 if root
, _
:= FindModuleRoot(cwd
, "", false); root
!= "" {
143 cfg
.GoModInGOPATH
= filepath
.Join(root
, "go.mod")
149 // Running 'go mod init': go.mod will be created in current directory.
152 ModRoot
, _
= FindModuleRoot(cwd
, "", MustUseModules
)
157 if search
.InDir(ModRoot
, os
.TempDir()) == "." {
158 // If you create /tmp/go.mod for experimenting,
159 // then any tests that create work directories under /tmp
160 // will find it and get modules when they're not expecting them.
161 // It's a bit of a peculiar thing to disallow but quite mysterious
162 // when it happens. See golang.org/issue/26708.
164 fmt
.Fprintf(os
.Stderr
, "go: warning: ignoring go.mod in system temp root %v\n", os
.TempDir())
170 cfg
.ModulesEnabled
= true
171 load
.ModBinDir
= BinDir
172 load
.ModLookup
= Lookup
173 load
.ModPackageModuleInfo
= PackageModuleInfo
174 load
.ModImportPaths
= ImportPaths
175 load
.ModPackageBuildInfo
= PackageBuildInfo
176 load
.ModInfoProg
= ModInfoProg
177 load
.ModImportFromFiles
= ImportFromFiles
178 load
.ModDirImportPath
= DirImportPath
180 search
.SetModRoot(ModRoot
)
186 // Set modfetch.PkgMod unconditionally, so that go clean -modcache can run even without modules enabled.
187 if list
:= filepath
.SplitList(cfg
.BuildContext
.GOPATH
); len(list
) > 0 && list
[0] != "" {
188 modfetch
.PkgMod
= filepath
.Join(list
[0], "pkg/mod")
192 // Enabled reports whether modules are (or must be) enabled.
193 // If modules must be enabled but are not, Enabled returns true
194 // and then the first use of module information will call die
195 // (usually through InitMod and MustInit).
196 func Enabled() bool {
198 panic("go: Enabled called before Init")
200 return ModRoot
!= "" || MustUseModules
203 // MustInit calls Init if needed and checks that
204 // modules are enabled and the main module has been found.
205 // If not, MustInit calls base.Fatalf with an appropriate message.
207 if Init(); ModRoot
== "" {
210 if c
:= cache
.Default(); c
== nil {
211 // With modules, there are no install locations for packages
212 // other than the build cache.
213 base
.Fatalf("go: cannot use modules with build cache disabled")
217 // Failed reports whether module loading failed.
218 // If Failed returns true, then any use of module information will call die.
221 return cfg
.ModulesEnabled
&& ModRoot
== ""
225 if os
.Getenv("GO111MODULE") == "off" {
226 base
.Fatalf("go: modules disabled by GO111MODULE=off; see 'go help modules'")
228 if inGOPATH
&& !MustUseModules
{
229 base
.Fatalf("go: modules disabled inside GOPATH/src by GO111MODULE=auto; see 'go help modules'")
231 base
.Fatalf("go: cannot find main module; see 'go help modules'")
240 list
:= filepath
.SplitList(cfg
.BuildContext
.GOPATH
)
241 if len(list
) == 0 || list
[0] == "" {
242 base
.Fatalf("missing $GOPATH")
245 if _
, err
:= os
.Stat(filepath
.Join(gopath
, "go.mod")); err
== nil {
246 base
.Fatalf("$GOPATH/go.mod exists but should not")
249 oldSrcMod
:= filepath
.Join(list
[0], "src/mod")
250 pkgMod
:= filepath
.Join(list
[0], "pkg/mod")
251 infoOld
, errOld
:= os
.Stat(oldSrcMod
)
252 _
, errMod
:= os
.Stat(pkgMod
)
253 if errOld
== nil && infoOld
.IsDir() && errMod
!= nil && os
.IsNotExist(errMod
) {
254 os
.Rename(oldSrcMod
, pkgMod
)
257 modfetch
.PkgMod
= pkgMod
258 modfetch
.GoSumFile
= filepath
.Join(ModRoot
, "go.sum")
259 codehost
.WorkRoot
= filepath
.Join(pkgMod
, "cache/vcs")
262 // Running go mod init: do legacy module conversion
269 gomod
:= filepath
.Join(ModRoot
, "go.mod")
270 data
, err
:= ioutil
.ReadFile(gomod
)
272 if os
.IsNotExist(err
) {
278 base
.Fatalf("go: %v", err
)
281 f
, err
:= modfile
.Parse(gomod
, data
, fixVersion
)
283 // Errors returned by modfile.Parse begin with file:line.
284 base
.Fatalf("go: errors parsing go.mod:\n%s\n", err
)
288 if len(f
.Syntax
.Stmt
) == 0 || f
.Module
== nil {
289 // Empty mod file. Must add module path.
290 path
, err
:= FindModulePath(ModRoot
)
292 base
.Fatalf("go: %v", err
)
294 f
.AddModuleStmt(path
)
297 if len(f
.Syntax
.Stmt
) == 1 && f
.Module
!= nil {
298 // Entire file is just a module statement.
299 // Populate require if possible.
303 excluded
= make(map[module
.Version
]bool)
304 for _
, x
:= range f
.Exclude
{
305 excluded
[x
.Mod
] = true
311 // modFileToBuildList initializes buildList from the modFile.
312 func modFileToBuildList() {
313 Target
= modFile
.Module
.Mod
314 list
:= []module
.Version
{Target
}
315 for _
, r
:= range modFile
.Require
{
316 list
= append(list
, r
.Mod
)
321 // Allowed reports whether module m is allowed (not excluded) by the main module's go.mod.
322 func Allowed(m module
.Version
) bool {
326 func legacyModInit() {
328 path
, err
:= FindModulePath(ModRoot
)
330 base
.Fatalf("go: %v", err
)
332 fmt
.Fprintf(os
.Stderr
, "go: creating new go.mod: module %s\n", path
)
333 modFile
= new(modfile
.File
)
334 modFile
.AddModuleStmt(path
)
337 for _
, name
:= range altConfigs
{
338 cfg
:= filepath
.Join(ModRoot
, name
)
339 data
, err
:= ioutil
.ReadFile(cfg
)
341 convert
:= modconv
.Converters
[name
]
345 fmt
.Fprintf(os
.Stderr
, "go: copying requirements from %s\n", base
.ShortPath(cfg
))
346 cfg
= filepath
.ToSlash(cfg
)
347 if err
:= modconv
.ConvertLegacyConfig(modFile
, cfg
, data
); err
!= nil {
348 base
.Fatalf("go: %v", err
)
350 if len(modFile
.Syntax
.Stmt
) == 1 {
351 // Add comment to avoid re-converting every time it runs.
352 modFile
.AddComment("// go: no requirements found in " + name
)
359 var altConfigs
= []string{
363 "Godeps/Godeps.json",
369 "vendor/vendor.json",
374 // Exported only for testing.
375 func FindModuleRoot(dir
, limit
string, legacyConfigOK
bool) (root
, file
string) {
376 dir
= filepath
.Clean(dir
)
378 limit
= filepath
.Clean(limit
)
380 // Look for enclosing go.mod.
382 if _
, err
:= os
.Stat(filepath
.Join(dir
, "go.mod")); err
== nil {
388 d
:= filepath
.Dir(dir
)
395 // Failing that, look for enclosing alternate version config.
399 for _
, name
:= range altConfigs
{
400 if _
, err
:= os
.Stat(filepath
.Join(dir
, name
)); err
== nil {
407 d
:= filepath
.Dir(dir
)
418 // Exported only for testing.
419 func FindModulePath(dir
string) (string, error
) {
420 if CmdModModule
!= "" {
421 // Running go mod init x/y/z; return x/y/z.
422 return CmdModModule
, nil
425 // Cast about for import comments,
426 // first in top-level directory, then in subdirectories.
427 list
, _
:= ioutil
.ReadDir(dir
)
428 for _
, info
:= range list
{
429 if info
.Mode().IsRegular() && strings
.HasSuffix(info
.Name(), ".go") {
430 if com
:= findImportComment(filepath
.Join(dir
, info
.Name())); com
!= "" {
435 for _
, info1
:= range list
{
437 files
, _
:= ioutil
.ReadDir(filepath
.Join(dir
, info1
.Name()))
438 for _
, info2
:= range files
{
439 if info2
.Mode().IsRegular() && strings
.HasSuffix(info2
.Name(), ".go") {
440 if com
:= findImportComment(filepath
.Join(dir
, info1
.Name(), info2
.Name())); com
!= "" {
441 return path
.Dir(com
), nil
448 // Look for Godeps.json declaring import path.
449 data
, _
:= ioutil
.ReadFile(filepath
.Join(dir
, "Godeps/Godeps.json"))
450 var cfg1
struct{ ImportPath
string }
451 json
.Unmarshal(data
, &cfg1
)
452 if cfg1
.ImportPath
!= "" {
453 return cfg1
.ImportPath
, nil
456 // Look for vendor.json declaring import path.
457 data
, _
= ioutil
.ReadFile(filepath
.Join(dir
, "vendor/vendor.json"))
458 var cfg2
struct{ RootPath
string }
459 json
.Unmarshal(data
, &cfg2
)
460 if cfg2
.RootPath
!= "" {
461 return cfg2
.RootPath
, nil
464 // Look for path in GOPATH.
465 for _
, gpdir
:= range filepath
.SplitList(cfg
.BuildContext
.GOPATH
) {
469 if rel
:= search
.InDir(dir
, filepath
.Join(gpdir
, "src")); rel
!= "" && rel
!= "." {
470 return filepath
.ToSlash(rel
), nil
474 // Look for .git/config with github origin as last resort.
475 data
, _
= ioutil
.ReadFile(filepath
.Join(dir
, ".git/config"))
476 if m
:= gitOriginRE
.FindSubmatch(data
); m
!= nil {
477 return "github.com/" + string(m
[1]), nil
480 return "", fmt
.Errorf("cannot determine module path for source directory %s (outside GOPATH, no import comments)", dir
)
484 gitOriginRE
= regexp
.MustCompile(`(?m)^\[remote "origin"\]\r?\n\turl = (?:https://github.com/|git@github.com:|gh:)([^/]+/[^/]+?)(\.git)?\r?\n`)
485 importCommentRE
= regexp
.MustCompile(`(?m)^package[ \t]+[^ \t\r\n/]+[ \t]+//[ \t]+import[ \t]+(\"[^"]+\")[ \t]*\r?\n`)
488 func findImportComment(file
string) string {
489 data
, err
:= ioutil
.ReadFile(file
)
493 m
:= importCommentRE
.FindSubmatch(data
)
497 path
, err
:= strconv
.Unquote(string(m
[1]))
504 var allowWriteGoMod
= true
506 // DisallowWriteGoMod causes future calls to WriteGoMod to do nothing at all.
507 func DisallowWriteGoMod() {
508 allowWriteGoMod
= false
511 // AllowWriteGoMod undoes the effect of DisallowWriteGoMod:
512 // future calls to WriteGoMod will update go.mod if needed.
513 // Note that any past calls have been discarded, so typically
514 // a call to AlowWriteGoMod should be followed by a call to WriteGoMod.
515 func AllowWriteGoMod() {
516 allowWriteGoMod
= true
519 // MinReqs returns a Reqs with minimal dependencies of Target,
520 // as will be written to go.mod.
521 func MinReqs() mvs
.Reqs
{
523 for _
, m
:= range buildList
[1:] {
524 if loaded
.direct
[m
.Path
] {
525 direct
= append(direct
, m
.Path
)
528 min
, err
:= mvs
.Req(Target
, buildList
, direct
, Reqs())
530 base
.Fatalf("go: %v", err
)
532 return &mvsReqs
{buildList
: append([]module
.Version
{Target
}, min
...)}
535 // WriteGoMod writes the current build list back to go.mod.
537 // If we're using -mod=vendor we basically ignored
538 // go.mod, so definitely don't try to write back our
539 // incomplete view of the world.
540 if !allowWriteGoMod || cfg
.BuildMod
== "vendor" {
546 min
, err
:= reqs
.Required(Target
)
548 base
.Fatalf("go: %v", err
)
550 var list
[]*modfile
.Require
551 for _
, m
:= range min
{
552 list
= append(list
, &modfile
.Require
{
554 Indirect
: !loaded
.direct
[m
.Path
],
557 modFile
.SetRequire(list
)
560 file
:= filepath
.Join(ModRoot
, "go.mod")
561 old
, _
:= ioutil
.ReadFile(file
)
562 modFile
.Cleanup() // clean file after edits
563 new, err
:= modFile
.Format()
565 base
.Fatalf("go: %v", err
)
567 if !bytes
.Equal(old
, new) {
568 if cfg
.BuildMod
== "readonly" {
569 base
.Fatalf("go: updates to go.mod needed, disabled by -mod=readonly")
571 if err
:= ioutil
.WriteFile(file
, new, 0666); err
!= nil {
572 base
.Fatalf("go: %v", err
)
575 modfetch
.WriteGoSum()
578 func fixVersion(path
, vers
string) (string, error
) {
579 // Special case: remove the old -gopkgin- hack.
580 if strings
.HasPrefix(path
, "gopkg.in/") && strings
.Contains(vers
, "-gopkgin-") {
581 vers
= vers
[strings
.Index(vers
, "-gopkgin-")+len("-gopkgin-"):]
584 // fixVersion is called speculatively on every
585 // module, version pair from every go.mod file.
586 // Avoid the query if it looks OK.
587 _
, pathMajor
, ok
:= module
.SplitPathVersion(path
)
589 return "", fmt
.Errorf("malformed module path: %s", path
)
591 if vers
!= "" && module
.CanonicalVersion(vers
) == vers
&& module
.MatchPathMajor(vers
, pathMajor
) {
595 info
, err
:= Query(path
, vers
, nil)
599 return info
.Version
, nil