1
0
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:
Russ Cox 2024-05-08 20:41:38 -04:00 committed by Gopher Robot
parent 0222a028f1
commit 6ccd8e4cf6
9 changed files with 340 additions and 46 deletions

View File

@ -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.

View File

@ -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

View File

@ -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)

View File

@ -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)

View File

@ -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)
}

View File

@ -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) {

View File

@ -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

View File

@ -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

View File

@ -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