return "<StringsFlag>"
}
+// explicitStringFlag is like a regular string flag, but it also tracks whether
+// the string was set explicitly to a non-empty value.
+type explicitStringFlag struct {
+ value *string
+ explicit *bool
+}
+
+func (f explicitStringFlag) String() string {
+ if f.value == nil {
+ return ""
+ }
+ return *f.value
+}
+
+func (f explicitStringFlag) Set(v string) error {
+ *f.value = v
+ if v != "" {
+ *f.explicit = true
+ }
+ return nil
+}
+
// AddBuildFlagsNX adds the -n and -x build flags to the flag set.
func AddBuildFlagsNX(flags *flag.FlagSet) {
flags.BoolVar(&cfg.BuildN, "n", false, "")
flags.BoolVar(&cfg.BuildX, "x", false, "")
}
-// AddLoadFlags adds the -mod build flag to the flag set.
-func AddLoadFlags(flags *flag.FlagSet) {
- flags.StringVar(&cfg.BuildMod, "mod", "", "")
+// AddModFlag adds the -mod build flag to the flag set.
+func AddModFlag(flags *flag.FlagSet) {
+ flags.Var(explicitStringFlag{value: &cfg.BuildMod, explicit: &cfg.BuildModExplicit}, "mod", "")
+}
+
+// AddModCommonFlags adds the module-related flags common to build commands
+// and 'go mod' subcommands.
+func AddModCommonFlags(flags *flag.FlagSet) {
+ flags.BoolVar(&cfg.ModCacheRW, "modcacherw", false, "")
+ flags.StringVar(&cfg.ModFile, "modfile", "", "")
}
BuildBuildmode string // -buildmode flag
BuildContext = defaultContext()
BuildMod string // -mod flag
- BuildModReason string // reason -mod flag is set, if set by default
+ BuildModExplicit bool // whether -mod was set explicitly
+ BuildModReason string // reason -mod was set, if set by default
BuildI bool // -i flag
BuildLinkshared bool // -linkshared flag
BuildMSan bool // -msan flag
func init() {
base.AddBuildFlagsNX(&CmdFmt.Flag)
- base.AddLoadFlags(&CmdFmt.Flag)
+ base.AddModFlag(&CmdFmt.Flag)
+ base.AddModCommonFlags(&CmdFmt.Flag)
}
var CmdFmt = &base.Command{
"cmd/go/internal/cfg"
"cmd/go/internal/modfetch"
"cmd/go/internal/modload"
- "cmd/go/internal/work"
"golang.org/x/mod/module"
)
// TODO(jayconrod): https://golang.org/issue/35849 Apply -x to other 'go mod' commands.
cmdDownload.Flag.BoolVar(&cfg.BuildX, "x", false, "")
- work.AddModCommonFlags(cmdDownload)
+ base.AddModCommonFlags(&cmdDownload.Flag)
}
type moduleJSON struct {
"cmd/go/internal/lockedfile"
"cmd/go/internal/modfetch"
"cmd/go/internal/modload"
- "cmd/go/internal/work"
"golang.org/x/mod/modfile"
"golang.org/x/mod/module"
cmdEdit.Flag.Var(flagFunc(flagRetract), "retract", "")
cmdEdit.Flag.Var(flagFunc(flagDropRetract), "dropretract", "")
- work.AddModCommonFlags(cmdEdit)
+ base.AddModCommonFlags(&cmdEdit.Flag)
base.AddBuildFlagsNX(&cmdEdit.Flag)
}
"cmd/go/internal/base"
"cmd/go/internal/cfg"
"cmd/go/internal/modload"
- "cmd/go/internal/work"
"golang.org/x/mod/module"
)
}
func init() {
- work.AddModCommonFlags(cmdGraph)
+ base.AddModCommonFlags(&cmdGraph.Flag)
}
func runGraph(ctx context.Context, cmd *base.Command, args []string) {
import (
"cmd/go/internal/base"
"cmd/go/internal/modload"
- "cmd/go/internal/work"
"context"
"os"
"strings"
}
func init() {
- work.AddModCommonFlags(cmdInit)
+ base.AddModCommonFlags(&cmdInit.Flag)
}
func runInit(ctx context.Context, cmd *base.Command, args []string) {
"cmd/go/internal/base"
"cmd/go/internal/cfg"
"cmd/go/internal/modload"
- "cmd/go/internal/work"
"context"
)
func init() {
cmdTidy.Run = runTidy // break init cycle
cmdTidy.Flag.BoolVar(&cfg.BuildV, "v", false, "")
- work.AddModCommonFlags(cmdTidy)
+ base.AddModCommonFlags(&cmdTidy.Flag)
}
func runTidy(ctx context.Context, cmd *base.Command, args []string) {
"cmd/go/internal/cfg"
"cmd/go/internal/imports"
"cmd/go/internal/modload"
- "cmd/go/internal/work"
"golang.org/x/mod/module"
"golang.org/x/mod/semver"
func init() {
cmdVendor.Flag.BoolVar(&cfg.BuildV, "v", false, "")
- work.AddModCommonFlags(cmdVendor)
+ base.AddModCommonFlags(&cmdVendor.Flag)
}
func runVendor(ctx context.Context, cmd *base.Command, args []string) {
"cmd/go/internal/cfg"
"cmd/go/internal/modfetch"
"cmd/go/internal/modload"
- "cmd/go/internal/work"
"golang.org/x/mod/module"
"golang.org/x/mod/sumdb/dirhash"
}
func init() {
- work.AddModCommonFlags(cmdVerify)
+ base.AddModCommonFlags(&cmdVerify.Flag)
}
func runVerify(ctx context.Context, cmd *base.Command, args []string) {
"cmd/go/internal/base"
"cmd/go/internal/modload"
- "cmd/go/internal/work"
"golang.org/x/mod/module"
)
func init() {
cmdWhy.Run = runWhy // break init cycle
- work.AddModCommonFlags(cmdWhy)
+ base.AddModCommonFlags(&cmdWhy.Flag)
}
func runWhy(ctx context.Context, cmd *base.Command, args []string) {
// setDefaultBuildMod sets a default value for cfg.BuildMod
// if it is currently empty.
func setDefaultBuildMod() {
- if cfg.BuildMod != "" {
+ if cfg.BuildModExplicit {
// Don't override an explicit '-mod=' argument.
return
}
- cfg.BuildMod = "mod"
+
if cfg.CmdName == "get" || strings.HasPrefix(cfg.CmdName, "mod ") {
- // Don't set -mod implicitly for commands whose purpose is to
- // manipulate the build list.
+ // 'get' and 'go mod' commands may update go.mod automatically.
+ // TODO(jayconrod): should this narrower? Should 'go mod download' or
+ // 'go mod graph' update go.mod by default?
+ cfg.BuildMod = "mod"
return
}
if modRoot == "" {
+ cfg.BuildMod = "mod"
return
}
}
}
- // Since a vendor directory exists, we have a non-trivial reason for
- // choosing -mod=mod, although it probably won't be used for anything.
- // Record the reason anyway for consistency.
- // It may be overridden if we switch to mod=readonly below.
- cfg.BuildModReason = fmt.Sprintf("Go version in go.mod is %s.", modGo)
+ // Since a vendor directory exists, we should record why we didn't use it.
+ // This message won't normally be shown, but it may appear with import errors.
+ cfg.BuildModReason = fmt.Sprintf("Go version in go.mod is %s, so vendor directory was not used.", modGo)
}
p := ModFilePath()
if fi, err := os.Stat(p); err == nil && !hasWritePerm(p, fi) {
cfg.BuildMod = "readonly"
cfg.BuildModReason = "go.mod file is read-only."
+ return
}
+ cfg.BuildMod = "mod"
}
func legacyModInit() {
// prefer to report a dirty go.mod over a dirty go.sum
if cfg.BuildModReason != "" {
base.Fatalf("go: updates to go.mod needed, disabled by -mod=readonly\n\t(%s)", cfg.BuildModReason)
- } else {
+ } else if cfg.BuildModExplicit {
base.Fatalf("go: updates to go.mod needed, disabled by -mod=readonly")
}
}
// AddBuildFlags adds the flags common to the build, clean, get,
// install, list, run, and test commands.
func AddBuildFlags(cmd *base.Command, mask BuildFlagMask) {
+ base.AddBuildFlagsNX(&cmd.Flag)
cmd.Flag.BoolVar(&cfg.BuildA, "a", false, "")
- cmd.Flag.BoolVar(&cfg.BuildN, "n", false, "")
cmd.Flag.IntVar(&cfg.BuildP, "p", cfg.BuildP, "")
if mask&OmitVFlag == 0 {
cmd.Flag.BoolVar(&cfg.BuildV, "v", false, "")
}
- cmd.Flag.BoolVar(&cfg.BuildX, "x", false, "")
cmd.Flag.Var(&load.BuildAsmflags, "asmflags", "")
cmd.Flag.Var(buildCompiler{}, "compiler", "")
cmd.Flag.Var(&load.BuildGcflags, "gcflags", "")
cmd.Flag.Var(&load.BuildGccgoflags, "gccgoflags", "")
if mask&OmitModFlag == 0 {
- cmd.Flag.StringVar(&cfg.BuildMod, "mod", "", "")
+ base.AddModFlag(&cmd.Flag)
}
if mask&OmitModCommonFlags == 0 {
- AddModCommonFlags(cmd)
+ base.AddModCommonFlags(&cmd.Flag)
}
cmd.Flag.StringVar(&cfg.BuildContext.InstallSuffix, "installsuffix", "", "")
cmd.Flag.Var(&load.BuildLdflags, "ldflags", "")
cmd.Flag.StringVar(&cfg.DebugTrace, "debug-trace", "", "")
}
-// AddModCommonFlags adds the module-related flags common to build commands
-// and 'go mod' subcommands.
-func AddModCommonFlags(cmd *base.Command) {
- cmd.Flag.BoolVar(&cfg.ModCacheRW, "modcacherw", false, "")
- cmd.Flag.StringVar(&cfg.ModFile, "modfile", "", "")
-}
-
// tagsFlag is the implementation of the -tags flag.
type tagsFlag []string
switch cfg.BuildMod {
case "":
- // ok
+ // Behavior will be determined automatically, as if no flag were passed.
case "readonly", "vendor", "mod":
if !cfg.ModulesEnabled && !inGOFLAGS("-mod") {
base.Fatalf("build flag -mod=%s only valid when using modules", cfg.BuildMod)