mirror of
https://github.com/golang/go
synced 2024-11-26 04:07:59 -07:00
cmd/go: add support for godebug lines in go.mod and go.work
The fact that the go line sets both the language version and the GODEBUG compatibility version can be a problem, especially since the go line is also required to be ≥ the go lines of any required dependency modules. This change adds a new 'godebug' line to go.mod and go.work to allow setting the GODEBUG values for the entire module. It also adds a new meta-value default=go1.21 that means take the defaults from Go 1.21 no matter what the go line says. These were discussed in proposal #65573. Fixes #65573. Change-Id: I91746322a10178370ed1015ce5278372a024c824 Reviewed-on: https://go-review.googlesource.com/c/go/+/584476 Auto-Submit: Russ Cox <rsc@golang.org> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Sam Thanawalla <samthanawalla@google.com> Reviewed-by: Michael Matloob <matloob@golang.org>
This commit is contained in:
parent
0222a028f1
commit
6ccd8e4cf6
@ -88,14 +88,38 @@ Because this method of setting GODEBUG defaults was introduced only in Go 1.21,
|
|||||||
programs listing versions of Go earlier than Go 1.20 are configured to match Go 1.20,
|
programs listing versions of Go earlier than Go 1.20 are configured to match Go 1.20,
|
||||||
not the older version.
|
not the older version.
|
||||||
|
|
||||||
To override these defaults, a main package's source files
|
To override these defaults, starting in Go 1.23, the work module's `go.mod`
|
||||||
|
or the workspace's `go.work` can list one or more `godebug` lines:
|
||||||
|
|
||||||
|
godebug (
|
||||||
|
default=go1.21
|
||||||
|
panicnil=1
|
||||||
|
asynctimerchan=0
|
||||||
|
)
|
||||||
|
|
||||||
|
The special key `default` indicates a Go version to take unspecified
|
||||||
|
settings from. This allows setting the GODEBUG defaults separately
|
||||||
|
from the Go language version in the module.
|
||||||
|
In this example, the program is asking for Go 1.21 semantics and
|
||||||
|
then asking for the old pre-Go 1.21 `panic(nil)` behavior and the
|
||||||
|
new Go 1.23 `asynctimerchan=0` behavior.
|
||||||
|
|
||||||
|
Only the work module's `go.mod` is consulted for `godebug` directives.
|
||||||
|
Any directives in required dependency modules are ignored.
|
||||||
|
It is an error to list a `godebug` with an unrecognized setting.
|
||||||
|
(Toolchains older than Go 1.23 reject all `godebug` lines, since they do not
|
||||||
|
understand `godebug` at all.)
|
||||||
|
|
||||||
|
The defaults from the `go` and `godebug` lines apply to all main
|
||||||
|
packages that are built. For more fine-grained control,
|
||||||
|
starting in Go 1.21, a main package's source files
|
||||||
can include one or more `//go:debug` directives at the top of the file
|
can include one or more `//go:debug` directives at the top of the file
|
||||||
(preceding the `package` statement).
|
(preceding the `package` statement).
|
||||||
Continuing the `panicnil` example, if the module or workspace is updated
|
The `godebug` lines in the previous example would be written:
|
||||||
to say `go` `1.21`, the program can opt back into the old `panic(nil)`
|
|
||||||
behavior by including this directive:
|
|
||||||
|
|
||||||
|
//go:debug default=go1.21
|
||||||
//go:debug panicnil=1
|
//go:debug panicnil=1
|
||||||
|
//go:debug asynctimerchan=0
|
||||||
|
|
||||||
Starting in Go 1.21, the Go toolchain treats a `//go:debug` directive
|
Starting in Go 1.21, the Go toolchain treats a `//go:debug` directive
|
||||||
with an unrecognized GODEBUG setting as an invalid program.
|
with an unrecognized GODEBUG setting as an invalid program.
|
||||||
|
@ -1201,6 +1201,12 @@
|
|||||||
//
|
//
|
||||||
// The -module flag changes the module's path (the go.mod file's module line).
|
// The -module flag changes the module's path (the go.mod file's module line).
|
||||||
//
|
//
|
||||||
|
// The -godebug=key=value flag adds a godebug key=value line,
|
||||||
|
// replacing any existing godebug lines with the given key.
|
||||||
|
//
|
||||||
|
// The -dropgodebug=key flag drops any existing godebug lines
|
||||||
|
// with the given key.
|
||||||
|
//
|
||||||
// The -require=path@version and -droprequire=path flags
|
// The -require=path@version and -droprequire=path flags
|
||||||
// add and drop a requirement on the given module path and version.
|
// add and drop a requirement on the given module path and version.
|
||||||
// Note that -require overrides any existing requirements on path.
|
// Note that -require overrides any existing requirements on path.
|
||||||
@ -1209,6 +1215,14 @@
|
|||||||
// which make other go.mod adjustments as needed to satisfy
|
// which make other go.mod adjustments as needed to satisfy
|
||||||
// constraints imposed by other modules.
|
// constraints imposed by other modules.
|
||||||
//
|
//
|
||||||
|
// The -go=version flag sets the expected Go language version.
|
||||||
|
// This flag is mainly for tools that understand Go version dependencies.
|
||||||
|
// Users should prefer 'go get go@version'.
|
||||||
|
//
|
||||||
|
// The -toolchain=version flag sets the Go toolchain to use.
|
||||||
|
// This flag is mainly for tools that understand Go version dependencies.
|
||||||
|
// Users should prefer 'go get toolchain@version'.
|
||||||
|
//
|
||||||
// The -exclude=path@version and -dropexclude=path@version flags
|
// The -exclude=path@version and -dropexclude=path@version flags
|
||||||
// add and drop an exclusion for the given module path and version.
|
// add and drop an exclusion for the given module path and version.
|
||||||
// Note that -exclude=path@version is a no-op if that exclusion already exists.
|
// Note that -exclude=path@version is a no-op if that exclusion already exists.
|
||||||
@ -1230,13 +1244,9 @@
|
|||||||
// like "v1.2.3" or a closed interval like "[v1.1.0,v1.1.9]". Note that
|
// like "v1.2.3" or a closed interval like "[v1.1.0,v1.1.9]". Note that
|
||||||
// -retract=version is a no-op if that retraction already exists.
|
// -retract=version is a no-op if that retraction already exists.
|
||||||
//
|
//
|
||||||
// The -require, -droprequire, -exclude, -dropexclude, -replace,
|
// The -godebug, -dropgodebug, -require, -droprequire, -exclude, -dropexclude,
|
||||||
// -dropreplace, -retract, and -dropretract editing flags may be repeated,
|
// -replace, -dropreplace, -retract, and -dropretract editing flags may be
|
||||||
// and the changes are applied in the order given.
|
// repeated, and the changes are applied in the order given.
|
||||||
//
|
|
||||||
// The -go=version flag sets the expected Go language version.
|
|
||||||
//
|
|
||||||
// The -toolchain=name flag sets the Go toolchain to use.
|
|
||||||
//
|
//
|
||||||
// The -print flag prints the final go.mod in its text format instead of
|
// The -print flag prints the final go.mod in its text format instead of
|
||||||
// writing it back to go.mod.
|
// writing it back to go.mod.
|
||||||
@ -1253,6 +1263,7 @@
|
|||||||
// Module ModPath
|
// Module ModPath
|
||||||
// Go string
|
// Go string
|
||||||
// Toolchain string
|
// Toolchain string
|
||||||
|
// Godebug []Godebug
|
||||||
// Require []Require
|
// Require []Require
|
||||||
// Exclude []Module
|
// Exclude []Module
|
||||||
// Replace []Replace
|
// Replace []Replace
|
||||||
@ -1264,9 +1275,14 @@
|
|||||||
// Deprecated string
|
// Deprecated string
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
|
// type Godebug struct {
|
||||||
|
// Key string
|
||||||
|
// Value string
|
||||||
|
// }
|
||||||
|
//
|
||||||
// type Require struct {
|
// type Require struct {
|
||||||
// Path string
|
// Path string
|
||||||
// Version string
|
// Version string
|
||||||
// Indirect bool
|
// Indirect bool
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
@ -1530,6 +1546,12 @@
|
|||||||
// rewrite the go.mod file. The only time this flag is needed is if no other
|
// rewrite the go.mod file. The only time this flag is needed is if no other
|
||||||
// flags are specified, as in 'go work edit -fmt'.
|
// flags are specified, as in 'go work edit -fmt'.
|
||||||
//
|
//
|
||||||
|
// The -godebug=key=value flag adds a godebug key=value line,
|
||||||
|
// replacing any existing godebug lines with the given key.
|
||||||
|
//
|
||||||
|
// The -dropgodebug=key flag drops any existing godebug lines
|
||||||
|
// with the given key.
|
||||||
|
//
|
||||||
// The -use=path and -dropuse=path flags
|
// The -use=path and -dropuse=path flags
|
||||||
// add and drop a use directive from the go.work file's set of module directories.
|
// add and drop a use directive from the go.work file's set of module directories.
|
||||||
//
|
//
|
||||||
@ -1561,10 +1583,16 @@
|
|||||||
// type GoWork struct {
|
// type GoWork struct {
|
||||||
// Go string
|
// Go string
|
||||||
// Toolchain string
|
// Toolchain string
|
||||||
|
// Godebug []Godebug
|
||||||
// Use []Use
|
// Use []Use
|
||||||
// Replace []Replace
|
// Replace []Replace
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
|
// type Godebug struct {
|
||||||
|
// Key string
|
||||||
|
// Value string
|
||||||
|
// }
|
||||||
|
//
|
||||||
// type Use struct {
|
// type Use struct {
|
||||||
// DiskPath string
|
// DiskPath string
|
||||||
// ModulePath string
|
// ModulePath string
|
||||||
|
@ -5,7 +5,6 @@
|
|||||||
package load
|
package load
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"cmd/go/internal/modload"
|
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"go/build"
|
"go/build"
|
||||||
@ -13,6 +12,9 @@ import (
|
|||||||
"sort"
|
"sort"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"cmd/go/internal/gover"
|
||||||
|
"cmd/go/internal/modload"
|
||||||
)
|
)
|
||||||
|
|
||||||
var ErrNotGoDebug = errors.New("not //go:debug line")
|
var ErrNotGoDebug = errors.New("not //go:debug line")
|
||||||
@ -32,25 +34,10 @@ func ParseGoDebug(text string) (key, value string, err error) {
|
|||||||
if !ok {
|
if !ok {
|
||||||
return "", "", fmt.Errorf("missing key=value")
|
return "", "", fmt.Errorf("missing key=value")
|
||||||
}
|
}
|
||||||
if strings.ContainsAny(k, " \t") {
|
if err := modload.CheckGodebug("//go:debug setting", k, v); err != nil {
|
||||||
return "", "", fmt.Errorf("key contains space")
|
return "", "", err
|
||||||
}
|
}
|
||||||
if strings.ContainsAny(v, " \t") {
|
return k, v, nil
|
||||||
return "", "", fmt.Errorf("value contains space")
|
|
||||||
}
|
|
||||||
if strings.ContainsAny(k, ",") {
|
|
||||||
return "", "", fmt.Errorf("key contains comma")
|
|
||||||
}
|
|
||||||
if strings.ContainsAny(v, ",") {
|
|
||||||
return "", "", fmt.Errorf("value contains comma")
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, info := range godebugs.All {
|
|
||||||
if k == info.Name {
|
|
||||||
return k, v, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return "", "", fmt.Errorf("unknown //go:debug setting %q", k)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// defaultGODEBUG returns the default GODEBUG setting for the main package p.
|
// defaultGODEBUG returns the default GODEBUG setting for the main package p.
|
||||||
@ -64,14 +51,21 @@ func defaultGODEBUG(p *Package, directives, testDirectives, xtestDirectives []bu
|
|||||||
if modload.RootMode == modload.NoRoot && p.Module != nil {
|
if modload.RootMode == modload.NoRoot && p.Module != nil {
|
||||||
// This is go install pkg@version or go run pkg@version.
|
// This is go install pkg@version or go run pkg@version.
|
||||||
// Use the Go version from the package.
|
// Use the Go version from the package.
|
||||||
// If there isn't one, then
|
// If there isn't one, then assume Go 1.20,
|
||||||
|
// the last version before GODEBUGs were introduced.
|
||||||
goVersion = p.Module.GoVersion
|
goVersion = p.Module.GoVersion
|
||||||
if goVersion == "" {
|
if goVersion == "" {
|
||||||
goVersion = "1.20"
|
goVersion = "1.20"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
m := godebugForGoVersion(goVersion)
|
var m map[string]string
|
||||||
|
for _, g := range modload.MainModules.Godebugs() {
|
||||||
|
if m == nil {
|
||||||
|
m = make(map[string]string)
|
||||||
|
}
|
||||||
|
m[g.Key] = g.Value
|
||||||
|
}
|
||||||
for _, list := range [][]build.Directive{p.Internal.Build.Directives, directives, testDirectives, xtestDirectives} {
|
for _, list := range [][]build.Directive{p.Internal.Build.Directives, directives, testDirectives, xtestDirectives} {
|
||||||
for _, d := range list {
|
for _, d := range list {
|
||||||
k, v, err := ParseGoDebug(d.Text)
|
k, v, err := ParseGoDebug(d.Text)
|
||||||
@ -84,6 +78,23 @@ func defaultGODEBUG(p *Package, directives, testDirectives, xtestDirectives []bu
|
|||||||
m[k] = v
|
m[k] = v
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if v, ok := m["default"]; ok {
|
||||||
|
delete(m, "default")
|
||||||
|
v = strings.TrimPrefix(v, "go")
|
||||||
|
if gover.IsValid(v) {
|
||||||
|
goVersion = v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
defaults := godebugForGoVersion(goVersion)
|
||||||
|
if defaults != nil {
|
||||||
|
// Apply m on top of defaults.
|
||||||
|
for k, v := range m {
|
||||||
|
defaults[k] = v
|
||||||
|
}
|
||||||
|
m = defaults
|
||||||
|
}
|
||||||
|
|
||||||
var keys []string
|
var keys []string
|
||||||
for k := range m {
|
for k := range m {
|
||||||
keys = append(keys, k)
|
keys = append(keys, k)
|
||||||
|
@ -44,6 +44,12 @@ flags are specified, as in 'go mod edit -fmt'.
|
|||||||
|
|
||||||
The -module flag changes the module's path (the go.mod file's module line).
|
The -module flag changes the module's path (the go.mod file's module line).
|
||||||
|
|
||||||
|
The -godebug=key=value flag adds a godebug key=value line,
|
||||||
|
replacing any existing godebug lines with the given key.
|
||||||
|
|
||||||
|
The -dropgodebug=key flag drops any existing godebug lines
|
||||||
|
with the given key.
|
||||||
|
|
||||||
The -require=path@version and -droprequire=path flags
|
The -require=path@version and -droprequire=path flags
|
||||||
add and drop a requirement on the given module path and version.
|
add and drop a requirement on the given module path and version.
|
||||||
Note that -require overrides any existing requirements on path.
|
Note that -require overrides any existing requirements on path.
|
||||||
@ -52,6 +58,14 @@ Users should prefer 'go get path@version' or 'go get path@none',
|
|||||||
which make other go.mod adjustments as needed to satisfy
|
which make other go.mod adjustments as needed to satisfy
|
||||||
constraints imposed by other modules.
|
constraints imposed by other modules.
|
||||||
|
|
||||||
|
The -go=version flag sets the expected Go language version.
|
||||||
|
This flag is mainly for tools that understand Go version dependencies.
|
||||||
|
Users should prefer 'go get go@version'.
|
||||||
|
|
||||||
|
The -toolchain=version flag sets the Go toolchain to use.
|
||||||
|
This flag is mainly for tools that understand Go version dependencies.
|
||||||
|
Users should prefer 'go get toolchain@version'.
|
||||||
|
|
||||||
The -exclude=path@version and -dropexclude=path@version flags
|
The -exclude=path@version and -dropexclude=path@version flags
|
||||||
add and drop an exclusion for the given module path and version.
|
add and drop an exclusion for the given module path and version.
|
||||||
Note that -exclude=path@version is a no-op if that exclusion already exists.
|
Note that -exclude=path@version is a no-op if that exclusion already exists.
|
||||||
@ -73,13 +87,9 @@ retraction on the given version. The version may be a single version
|
|||||||
like "v1.2.3" or a closed interval like "[v1.1.0,v1.1.9]". Note that
|
like "v1.2.3" or a closed interval like "[v1.1.0,v1.1.9]". Note that
|
||||||
-retract=version is a no-op if that retraction already exists.
|
-retract=version is a no-op if that retraction already exists.
|
||||||
|
|
||||||
The -require, -droprequire, -exclude, -dropexclude, -replace,
|
The -godebug, -dropgodebug, -require, -droprequire, -exclude, -dropexclude,
|
||||||
-dropreplace, -retract, and -dropretract editing flags may be repeated,
|
-replace, -dropreplace, -retract, and -dropretract editing flags may be
|
||||||
and the changes are applied in the order given.
|
repeated, and the changes are applied in the order given.
|
||||||
|
|
||||||
The -go=version flag sets the expected Go language version.
|
|
||||||
|
|
||||||
The -toolchain=name flag sets the Go toolchain to use.
|
|
||||||
|
|
||||||
The -print flag prints the final go.mod in its text format instead of
|
The -print flag prints the final go.mod in its text format instead of
|
||||||
writing it back to go.mod.
|
writing it back to go.mod.
|
||||||
@ -96,6 +106,7 @@ writing it back to go.mod. The JSON output corresponds to these Go types:
|
|||||||
Module ModPath
|
Module ModPath
|
||||||
Go string
|
Go string
|
||||||
Toolchain string
|
Toolchain string
|
||||||
|
Godebug []Godebug
|
||||||
Require []Require
|
Require []Require
|
||||||
Exclude []Module
|
Exclude []Module
|
||||||
Replace []Replace
|
Replace []Replace
|
||||||
@ -107,9 +118,14 @@ writing it back to go.mod. The JSON output corresponds to these Go types:
|
|||||||
Deprecated string
|
Deprecated string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Godebug struct {
|
||||||
|
Key string
|
||||||
|
Value string
|
||||||
|
}
|
||||||
|
|
||||||
type Require struct {
|
type Require struct {
|
||||||
Path string
|
Path string
|
||||||
Version string
|
Version string
|
||||||
Indirect bool
|
Indirect bool
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -155,12 +171,14 @@ func (f flagFunc) Set(s string) error { f(s); return nil }
|
|||||||
func init() {
|
func init() {
|
||||||
cmdEdit.Run = runEdit // break init cycle
|
cmdEdit.Run = runEdit // break init cycle
|
||||||
|
|
||||||
|
cmdEdit.Flag.Var(flagFunc(flagGodebug), "godebug", "")
|
||||||
|
cmdEdit.Flag.Var(flagFunc(flagDropGodebug), "dropgodebug", "")
|
||||||
cmdEdit.Flag.Var(flagFunc(flagRequire), "require", "")
|
cmdEdit.Flag.Var(flagFunc(flagRequire), "require", "")
|
||||||
cmdEdit.Flag.Var(flagFunc(flagDropRequire), "droprequire", "")
|
cmdEdit.Flag.Var(flagFunc(flagDropRequire), "droprequire", "")
|
||||||
cmdEdit.Flag.Var(flagFunc(flagExclude), "exclude", "")
|
cmdEdit.Flag.Var(flagFunc(flagExclude), "exclude", "")
|
||||||
cmdEdit.Flag.Var(flagFunc(flagDropReplace), "dropreplace", "")
|
|
||||||
cmdEdit.Flag.Var(flagFunc(flagReplace), "replace", "")
|
|
||||||
cmdEdit.Flag.Var(flagFunc(flagDropExclude), "dropexclude", "")
|
cmdEdit.Flag.Var(flagFunc(flagDropExclude), "dropexclude", "")
|
||||||
|
cmdEdit.Flag.Var(flagFunc(flagReplace), "replace", "")
|
||||||
|
cmdEdit.Flag.Var(flagFunc(flagDropReplace), "dropreplace", "")
|
||||||
cmdEdit.Flag.Var(flagFunc(flagRetract), "retract", "")
|
cmdEdit.Flag.Var(flagFunc(flagRetract), "retract", "")
|
||||||
cmdEdit.Flag.Var(flagFunc(flagDropRetract), "dropretract", "")
|
cmdEdit.Flag.Var(flagFunc(flagDropRetract), "dropretract", "")
|
||||||
|
|
||||||
@ -369,6 +387,28 @@ func allowedVersionArg(arg string) bool {
|
|||||||
return !modfile.MustQuote(arg)
|
return !modfile.MustQuote(arg)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// flagGodebug implements the -godebug flag.
|
||||||
|
func flagGodebug(arg string) {
|
||||||
|
key, value, ok := strings.Cut(arg, "=")
|
||||||
|
if !ok || strings.ContainsAny(arg, "\"`',") {
|
||||||
|
base.Fatalf("go: -godebug=%s: need key=value", arg)
|
||||||
|
}
|
||||||
|
edits = append(edits, func(f *modfile.File) {
|
||||||
|
if err := f.AddGodebug(key, value); err != nil {
|
||||||
|
base.Fatalf("go: -godebug=%s: %v", arg, err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// flagDropGodebug implements the -dropgodebug flag.
|
||||||
|
func flagDropGodebug(arg string) {
|
||||||
|
edits = append(edits, func(f *modfile.File) {
|
||||||
|
if err := f.DropGodebug(arg); err != nil {
|
||||||
|
base.Fatalf("go: -dropgodebug=%s: %v", arg, err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// flagRequire implements the -require flag.
|
// flagRequire implements the -require flag.
|
||||||
func flagRequire(arg string) {
|
func flagRequire(arg string) {
|
||||||
path, version := parsePathVersion("require", arg)
|
path, version := parsePathVersion("require", arg)
|
||||||
|
@ -10,6 +10,7 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"internal/godebugs"
|
||||||
"internal/lazyregexp"
|
"internal/lazyregexp"
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
@ -241,6 +242,27 @@ func (mms *MainModuleSet) GoVersion() string {
|
|||||||
return gover.DefaultGoModVersion
|
return gover.DefaultGoModVersion
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Godebugs returns the godebug lines set on the single module, in module mode,
|
||||||
|
// or on the go.work file in workspace mode.
|
||||||
|
// The caller must not modify the result.
|
||||||
|
func (mms *MainModuleSet) Godebugs() []*modfile.Godebug {
|
||||||
|
if inWorkspaceMode() {
|
||||||
|
if mms.workFile != nil {
|
||||||
|
return mms.workFile.Godebug
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if mms != nil && len(mms.versions) == 1 {
|
||||||
|
f := mms.ModFile(mms.mustGetSingleMainModule())
|
||||||
|
if f == nil {
|
||||||
|
// Special case: we are outside a module, like 'go run x.go'.
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return f.Godebug
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// Toolchain returns the toolchain set on the single module, in module mode,
|
// Toolchain returns the toolchain set on the single module, in module mode,
|
||||||
// or the go.work file in workspace mode.
|
// or the go.work file in workspace mode.
|
||||||
func (mms *MainModuleSet) Toolchain() string {
|
func (mms *MainModuleSet) Toolchain() string {
|
||||||
@ -675,6 +697,12 @@ func loadWorkFile(path string) (workFile *modfile.WorkFile, modRoots []string, e
|
|||||||
modRoots = append(modRoots, modRoot)
|
modRoots = append(modRoots, modRoot)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for _, g := range wf.Godebug {
|
||||||
|
if err := CheckGodebug("godebug", g.Key, g.Value); err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return wf, modRoots, nil
|
return wf, modRoots, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -914,6 +942,19 @@ func loadModFile(ctx context.Context, opts *PackageOpts) (*Requirements, error)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !inWorkspaceMode() {
|
||||||
|
ok := true
|
||||||
|
for _, g := range f.Godebug {
|
||||||
|
if err := CheckGodebug("godebug", g.Key, g.Value); err != nil {
|
||||||
|
errs = append(errs, fmt.Errorf("%s: %v", base.ShortPath(filepath.Dir(gomod)), err))
|
||||||
|
ok = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
modFiles = append(modFiles, f)
|
modFiles = append(modFiles, f)
|
||||||
mainModule := f.Module.Mod
|
mainModule := f.Module.Mod
|
||||||
mainModules = append(mainModules, mainModule)
|
mainModules = append(mainModules, mainModule)
|
||||||
@ -1257,6 +1298,7 @@ func makeMainModules(ms []module.Version, rootDirs []string, modFiles []*modfile
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return mainModules
|
return mainModules
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2054,3 +2096,33 @@ func suggestGopkgIn(path string) string {
|
|||||||
}
|
}
|
||||||
return url + ".v" + m
|
return url + ".v" + m
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func CheckGodebug(verb, k, v string) error {
|
||||||
|
if strings.ContainsAny(k, " \t") {
|
||||||
|
return fmt.Errorf("key contains space")
|
||||||
|
}
|
||||||
|
if strings.ContainsAny(v, " \t") {
|
||||||
|
return fmt.Errorf("value contains space")
|
||||||
|
}
|
||||||
|
if strings.ContainsAny(k, ",") {
|
||||||
|
return fmt.Errorf("key contains comma")
|
||||||
|
}
|
||||||
|
if strings.ContainsAny(v, ",") {
|
||||||
|
return fmt.Errorf("value contains comma")
|
||||||
|
}
|
||||||
|
if k == "default" {
|
||||||
|
if !strings.HasPrefix(v, "go") || !gover.IsValid(v[len("go"):]) {
|
||||||
|
return fmt.Errorf("value for default= must be goVERSION")
|
||||||
|
}
|
||||||
|
if gover.Compare(v[len("go"):], gover.Local()) > 0 {
|
||||||
|
return fmt.Errorf("default=%s too new (toolchain is go%s)", v, gover.Local())
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
for _, info := range godebugs.All {
|
||||||
|
if k == info.Name {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return fmt.Errorf("unknown %s %q", verb, k)
|
||||||
|
}
|
||||||
|
@ -38,6 +38,12 @@ This reformatting is also implied by any other modifications that use or
|
|||||||
rewrite the go.mod file. The only time this flag is needed is if no other
|
rewrite the go.mod file. The only time this flag is needed is if no other
|
||||||
flags are specified, as in 'go work edit -fmt'.
|
flags are specified, as in 'go work edit -fmt'.
|
||||||
|
|
||||||
|
The -godebug=key=value flag adds a godebug key=value line,
|
||||||
|
replacing any existing godebug lines with the given key.
|
||||||
|
|
||||||
|
The -dropgodebug=key flag drops any existing godebug lines
|
||||||
|
with the given key.
|
||||||
|
|
||||||
The -use=path and -dropuse=path flags
|
The -use=path and -dropuse=path flags
|
||||||
add and drop a use directive from the go.work file's set of module directories.
|
add and drop a use directive from the go.work file's set of module directories.
|
||||||
|
|
||||||
@ -69,10 +75,16 @@ writing it back to go.mod. The JSON output corresponds to these Go types:
|
|||||||
type GoWork struct {
|
type GoWork struct {
|
||||||
Go string
|
Go string
|
||||||
Toolchain string
|
Toolchain string
|
||||||
|
Godebug []Godebug
|
||||||
Use []Use
|
Use []Use
|
||||||
Replace []Replace
|
Replace []Replace
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Godebug struct {
|
||||||
|
Key string
|
||||||
|
Value string
|
||||||
|
}
|
||||||
|
|
||||||
type Use struct {
|
type Use struct {
|
||||||
DiskPath string
|
DiskPath string
|
||||||
ModulePath string
|
ModulePath string
|
||||||
@ -110,6 +122,8 @@ func (f flagFunc) Set(s string) error { f(s); return nil }
|
|||||||
func init() {
|
func init() {
|
||||||
cmdEdit.Run = runEditwork // break init cycle
|
cmdEdit.Run = runEditwork // break init cycle
|
||||||
|
|
||||||
|
cmdEdit.Flag.Var(flagFunc(flagEditworkGodebug), "godebug", "")
|
||||||
|
cmdEdit.Flag.Var(flagFunc(flagEditworkDropGodebug), "dropgodebug", "")
|
||||||
cmdEdit.Flag.Var(flagFunc(flagEditworkUse), "use", "")
|
cmdEdit.Flag.Var(flagFunc(flagEditworkUse), "use", "")
|
||||||
cmdEdit.Flag.Var(flagFunc(flagEditworkDropUse), "dropuse", "")
|
cmdEdit.Flag.Var(flagFunc(flagEditworkDropUse), "dropuse", "")
|
||||||
cmdEdit.Flag.Var(flagFunc(flagEditworkReplace), "replace", "")
|
cmdEdit.Flag.Var(flagFunc(flagEditworkReplace), "replace", "")
|
||||||
@ -206,6 +220,28 @@ func runEditwork(ctx context.Context, cmd *base.Command, args []string) {
|
|||||||
modload.WriteWorkFile(gowork, workFile)
|
modload.WriteWorkFile(gowork, workFile)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// flagEditworkGodebug implements the -godebug flag.
|
||||||
|
func flagEditworkGodebug(arg string) {
|
||||||
|
key, value, ok := strings.Cut(arg, "=")
|
||||||
|
if !ok || strings.ContainsAny(arg, "\"`',") {
|
||||||
|
base.Fatalf("go: -godebug=%s: need key=value", arg)
|
||||||
|
}
|
||||||
|
workedits = append(workedits, func(f *modfile.WorkFile) {
|
||||||
|
if err := f.AddGodebug(key, value); err != nil {
|
||||||
|
base.Fatalf("go: -godebug=%s: %v", arg, err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// flagEditworkDropGodebug implements the -dropgodebug flag.
|
||||||
|
func flagEditworkDropGodebug(arg string) {
|
||||||
|
workedits = append(workedits, func(f *modfile.WorkFile) {
|
||||||
|
if err := f.DropGodebug(arg); err != nil {
|
||||||
|
base.Fatalf("go: -dropgodebug=%s: %v", arg, err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// flagEditworkUse implements the -use flag.
|
// flagEditworkUse implements the -use flag.
|
||||||
func flagEditworkUse(arg string) {
|
func flagEditworkUse(arg string) {
|
||||||
workedits = append(workedits, func(f *modfile.WorkFile) {
|
workedits = append(workedits, func(f *modfile.WorkFile) {
|
||||||
|
42
src/cmd/go/testdata/script/godebug_default.txt
vendored
42
src/cmd/go/testdata/script/godebug_default.txt
vendored
@ -45,6 +45,35 @@ cp go.mod.21 go.mod
|
|||||||
stderr 'go: module . listed in go.work file requires go >= 1.21'
|
stderr 'go: module . listed in go.work file requires go >= 1.21'
|
||||||
rm go.work
|
rm go.work
|
||||||
|
|
||||||
|
# Go 1.21 go.mod with godebug default=go1.20
|
||||||
|
rm go.work
|
||||||
|
cp go.mod.21 go.mod
|
||||||
|
go mod edit -godebug default=go1.20 -godebug asynctimerchan=0
|
||||||
|
go list -f '{{.Module.GoVersion}} {{.DefaultGODEBUG}}'
|
||||||
|
stdout panicnil=1
|
||||||
|
stdout asynctimerchan=0
|
||||||
|
|
||||||
|
# Go 1.21 go.work with godebug default=go1.20
|
||||||
|
cp go.work.21 go.work
|
||||||
|
go list -f '{{.Module.GoVersion}} {{.DefaultGODEBUG}}'
|
||||||
|
! stdout panicnil # go.work wins
|
||||||
|
stdout asynctimerchan=1 # go.work wins
|
||||||
|
go work edit -godebug default=go1.20 -godebug asynctimerchan=0
|
||||||
|
go list -f '{{.Module.GoVersion}} {{.DefaultGODEBUG}}'
|
||||||
|
stdout panicnil=1
|
||||||
|
stdout asynctimerchan=0
|
||||||
|
rm go.work
|
||||||
|
|
||||||
|
# Go 1.21 go.mod with //go:debug default=go1.20 in program
|
||||||
|
cp go.mod.21 go.mod
|
||||||
|
go list -tags godebug -f '{{.Module.GoVersion}} {{.DefaultGODEBUG}}'
|
||||||
|
stdout panicnil=1
|
||||||
|
stdout asynctimerchan=0
|
||||||
|
|
||||||
|
# Invalid //go:debug line should be diagnosed at build.
|
||||||
|
! go build -tags godebugbad
|
||||||
|
stderr 'invalid //go:debug: value contains space'
|
||||||
|
|
||||||
[short] skip
|
[short] skip
|
||||||
|
|
||||||
# Programs in Go 1.21 work module should trigger run-time error.
|
# Programs in Go 1.21 work module should trigger run-time error.
|
||||||
@ -105,6 +134,19 @@ func main() {
|
|||||||
panic(nil)
|
panic(nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
-- godebug.go --
|
||||||
|
//go:build godebug
|
||||||
|
//go:debug default=go1.20
|
||||||
|
//go:debug asynctimerchan=0
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
-- godebugbad.go --
|
||||||
|
//go:build godebugbad
|
||||||
|
//go:debug default=go1.20 asynctimerchan=0
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
-- q/go.mod --
|
-- q/go.mod --
|
||||||
go 1.20
|
go 1.20
|
||||||
module q
|
module q
|
||||||
|
20
src/cmd/go/testdata/script/mod_edit.txt
vendored
20
src/cmd/go/testdata/script/mod_edit.txt
vendored
@ -87,6 +87,16 @@ go mod init foo
|
|||||||
go mod edit -module local-only -require=other-local@v1.0.0 -replace other-local@v1.0.0=./other
|
go mod edit -module local-only -require=other-local@v1.0.0 -replace other-local@v1.0.0=./other
|
||||||
cmpenv go.mod go.mod.edit
|
cmpenv go.mod go.mod.edit
|
||||||
|
|
||||||
|
# go mod edit -godebug
|
||||||
|
cd $WORK/g
|
||||||
|
cp go.mod.start go.mod
|
||||||
|
go mod edit -godebug key=value
|
||||||
|
cmpenv go.mod go.mod.edit
|
||||||
|
go mod edit -dropgodebug key2
|
||||||
|
cmpenv go.mod go.mod.edit
|
||||||
|
go mod edit -dropgodebug key
|
||||||
|
cmpenv go.mod go.mod.start
|
||||||
|
|
||||||
-- x.go --
|
-- x.go --
|
||||||
package x
|
package x
|
||||||
|
|
||||||
@ -338,3 +348,13 @@ module m
|
|||||||
"Replace": null,
|
"Replace": null,
|
||||||
"Retract": null
|
"Retract": null
|
||||||
}
|
}
|
||||||
|
-- $WORK/g/go.mod.start --
|
||||||
|
module g
|
||||||
|
|
||||||
|
go 1.10
|
||||||
|
-- $WORK/g/go.mod.edit --
|
||||||
|
module g
|
||||||
|
|
||||||
|
go 1.10
|
||||||
|
|
||||||
|
godebug key=value
|
||||||
|
23
src/cmd/go/testdata/script/work_edit.txt
vendored
23
src/cmd/go/testdata/script/work_edit.txt
vendored
@ -34,9 +34,20 @@ cmp stdout go.work.want_print
|
|||||||
go work edit -json -go 1.19 -use b -dropuse c -replace 'x.1@v1.4.0 = ../z' -dropreplace x.1 -dropreplace x.1@v1.3.0
|
go work edit -json -go 1.19 -use b -dropuse c -replace 'x.1@v1.4.0 = ../z' -dropreplace x.1 -dropreplace x.1@v1.3.0
|
||||||
cmp stdout go.work.want_json
|
cmp stdout go.work.want_json
|
||||||
|
|
||||||
|
# go work edit -godebug
|
||||||
|
cd $WORK/g
|
||||||
|
cp go.work.start go.work
|
||||||
|
go work edit -godebug key=value
|
||||||
|
cmpenv go.work go.work.edit
|
||||||
|
go work edit -dropgodebug key2
|
||||||
|
cmpenv go.work go.work.edit
|
||||||
|
go work edit -dropgodebug key
|
||||||
|
cmpenv go.work go.work.start
|
||||||
|
|
||||||
|
# go work edit -print -fmt
|
||||||
env GOWORK=$GOPATH/src/unformatted
|
env GOWORK=$GOPATH/src/unformatted
|
||||||
go work edit -print -fmt
|
go work edit -print -fmt
|
||||||
cmp stdout formatted
|
cmp stdout $GOPATH/src/formatted
|
||||||
|
|
||||||
-- m/go.mod --
|
-- m/go.mod --
|
||||||
module m
|
module m
|
||||||
@ -164,3 +175,13 @@ replace (
|
|||||||
x.1 v1.3.0 => y.1 v1.4.0
|
x.1 v1.3.0 => y.1 v1.4.0
|
||||||
x.1 v1.4.0 => ../z
|
x.1 v1.4.0 => ../z
|
||||||
)
|
)
|
||||||
|
-- $WORK/g/go.work.start --
|
||||||
|
use g
|
||||||
|
|
||||||
|
go 1.10
|
||||||
|
-- $WORK/g/go.work.edit --
|
||||||
|
use g
|
||||||
|
|
||||||
|
go 1.10
|
||||||
|
|
||||||
|
godebug key=value
|
||||||
|
Loading…
Reference in New Issue
Block a user