<p><!-- https://golang.org/issue/45713 -->
The <code>go</code> command now supports a "Workspace" mode. If a
<code>go.work</code> file is found in the working directory or a
- parent directory, or one is specified using the <code>-workfile</code>
- flag, it will put the <code>go</code> command into workspace mode.
+ parent directory, or one is specified using the <code>GOWORK</code>
+ environment variable, it will put the <code>go</code> command into workspace mode.
In workspace mode, the <code>go.work</code> file will be used to
determine the set of main modules used as the roots for module
resolution, instead of using the normally-found <code>go.mod</code>
// directory, but it is not accessed. When -modfile is specified, an
// alternate go.sum file is also used: its path is derived from the
// -modfile flag by trimming the ".mod" extension and appending ".sum".
-// -workfile file
-// in module aware mode, use the given go.work file as a workspace file.
-// By default or when -workfile is "auto", the go command searches for a
-// file named go.work in the current directory and then containing directories
-// until one is found. If a valid go.work file is found, the modules
-// specified will collectively be used as the main modules. If -workfile
-// is "off", or a go.work file is not found in "auto" mode, workspace
-// mode is disabled.
// -overlay file
// read a JSON config file that provides an overlay for build operations.
// The file is a JSON struct with a single field, named 'Replace', that
// GOVCS
// Lists version control commands that may be used with matching servers.
// See 'go help vcs'.
+// GOWORK
+// In module aware mode, use the given go.work file as a workspace file.
+// By default or when GOWORK is "auto", the go command searches for a
+// file named go.work in the current directory and then containing directories
+// until one is found. If a valid go.work file is found, the modules
+// specified will collectively be used as the main modules. If GOWORK
+// is "off", or a go.work file is not found in "auto" mode, workspace
+// mode is disabled.
//
// Environment variables for use with cgo:
//
flags.Var(explicitStringFlag{value: &cfg.BuildMod, explicit: &cfg.BuildModExplicit}, "mod", "")
}
-// AddWorkfileFlag adds the workfile flag to the flag set. It enables workspace
-// mode for commands that support it by resetting the cfg.WorkFile variable
-// to "" (equivalent to auto) rather than off.
-func AddWorkfileFlag(flags *flag.FlagSet) {
- flags.Var(explicitStringFlag{value: &cfg.WorkFile, explicit: &cfg.WorkFileExplicit}, "workfile", "")
-}
-
// AddModCommonFlags adds the module-related flags common to build commands
// and 'go mod' subcommands.
func AddModCommonFlags(flags *flag.FlagSet) {
BuildWork bool // -work flag
BuildX bool // -x flag
- ModCacheRW bool // -modcacherw flag
- ModFile string // -modfile flag
- WorkFile string // -workfile flag
- WorkFileExplicit bool // whether -workfile was set explicitly
+ ModCacheRW bool // -modcacherw flag
+ ModFile string // -modfile flag
CmdName string // "build", "install", "list", "mod tidy", etc.
}
modload.InitWorkfile()
gowork := modload.WorkFilePath()
+ // As a special case, if a user set off explicitly, report that in GOWORK.
+ if cfg.Getenv("GOWORK") == "off" {
+ gowork = "off"
+ }
return []cfg.EnvVar{
{Name: "GOMOD", Value: gomod},
{Name: "GOWORK", Value: gowork},
GOVCS
Lists version control commands that may be used with matching servers.
See 'go help vcs'.
+ GOWORK
+ In module aware mode, use the given go.work file as a workspace file.
+ By default or when GOWORK is "auto", the go command searches for a
+ file named go.work in the current directory and then containing directories
+ until one is found. If a valid go.work file is found, the modules
+ specified will collectively be used as the main modules. If GOWORK
+ is "off", or a go.work file is not found in "auto" mode, workspace
+ mode is disabled.
Environment variables for use with cgo:
func init() {
CmdList.Run = runList // break init cycle
work.AddBuildFlags(CmdList, work.DefaultBuildFlags)
- base.AddWorkfileFlag(&CmdList.Flag)
}
var (
// TODO(jayconrod): https://golang.org/issue/35849 Apply -x to other 'go mod' commands.
cmdDownload.Flag.BoolVar(&cfg.BuildX, "x", false, "")
base.AddModCommonFlags(&cmdDownload.Flag)
- base.AddWorkfileFlag(&cmdDownload.Flag)
}
type moduleJSON struct {
func init() {
cmdGraph.Flag.Var(&graphGo, "go", "")
base.AddModCommonFlags(&cmdGraph.Flag)
- base.AddWorkfileFlag(&cmdGraph.Flag)
}
func runGraph(ctx context.Context, cmd *base.Command, args []string) {
func init() {
base.AddModCommonFlags(&cmdVerify.Flag)
- base.AddWorkfileFlag(&cmdVerify.Flag)
}
func runVerify(ctx context.Context, cmd *base.Command, args []string) {
func init() {
cmdWhy.Run = runWhy // break init cycle
base.AddModCommonFlags(&cmdWhy.Flag)
- base.AddWorkfileFlag(&cmdWhy.Flag)
}
func runWhy(ctx context.Context, cmd *base.Command, args []string) {
// operate in workspace mode. It should not be called by other commands,
// for example 'go mod tidy', that don't operate in workspace mode.
func InitWorkfile() {
- switch cfg.WorkFile {
+ switch gowork := cfg.Getenv("GOWORK"); gowork {
case "off":
workFilePath = ""
case "", "auto":
workFilePath = findWorkspaceFile(base.Cwd())
default:
- if !filepath.IsAbs(cfg.WorkFile) {
- base.Fatalf("the path provided to -workfile must be an absolute path")
+ if !filepath.IsAbs(gowork) {
+ base.Fatalf("the path provided to GOWORK must be an absolute path")
}
- workFilePath = cfg.WorkFile
+ workFilePath = gowork
}
}
if inWorkspaceMode() && cfg.BuildMod != "readonly" {
base.Fatalf("go: -mod may only be set to readonly when in workspace mode, but it is set to %q"+
"\n\tRemove the -mod flag to use the default readonly value,"+
- "\n\tor set -workfile=off to disable workspace mode.", cfg.BuildMod)
+ "\n\tor set GOWORK=off to disable workspace mode.", cfg.BuildMod)
}
// Don't override an explicit '-mod=' argument.
return
CmdRun.Run = runRun // break init loop
work.AddBuildFlags(CmdRun, work.DefaultBuildFlags)
- base.AddWorkfileFlag(&CmdRun.Flag)
CmdRun.Flag.Var((*base.StringsFlag)(&work.ExecCmd), "exec", "")
}
func init() {
work.AddBuildFlags(CmdTest, work.OmitVFlag)
- base.AddWorkfileFlag(&CmdTest.Flag)
cf := CmdTest.Flag
cf.BoolVar(&testC, "c", false, "")
directory, but it is not accessed. When -modfile is specified, an
alternate go.sum file is also used: its path is derived from the
-modfile flag by trimming the ".mod" extension and appending ".sum".
- -workfile file
- in module aware mode, use the given go.work file as a workspace file.
- By default or when -workfile is "auto", the go command searches for a
- file named go.work in the current directory and then containing directories
- until one is found. If a valid go.work file is found, the modules
- specified will collectively be used as the main modules. If -workfile
- is "off", or a go.work file is not found in "auto" mode, workspace
- mode is disabled.
-overlay file
read a JSON config file that provides an overlay for build operations.
The file is a JSON struct with a single field, named 'Replace', that
AddBuildFlags(CmdBuild, DefaultBuildFlags)
AddBuildFlags(CmdInstall, DefaultBuildFlags)
- base.AddWorkfileFlag(&CmdBuild.Flag)
}
// Note that flags consulted by other parts of the code
cmdEdit.Flag.Var(flagFunc(flagEditworkDropUse), "dropuse", "")
cmdEdit.Flag.Var(flagFunc(flagEditworkReplace), "replace", "")
cmdEdit.Flag.Var(flagFunc(flagEditworkDropReplace), "dropreplace", "")
-
- base.AddWorkfileFlag(&cmdEdit.Flag)
}
func runEditwork(ctx context.Context, cmd *base.Command, args []string) {
}
if gowork == "" {
- base.Fatalf("go: no go.work file found\n\t(run 'go work init' first or specify path using -workfile flag)")
+ base.Fatalf("go: no go.work file found\n\t(run 'go work init' first or specify path using GOWORK environment variable)")
}
anyFlags :=
func init() {
base.AddModCommonFlags(&cmdInit.Flag)
- base.AddWorkfileFlag(&cmdInit.Flag)
}
func runInit(ctx context.Context, cmd *base.Command, args []string) {
modload.ForceUseModules = true
- // TODO(matloob): support using the -workfile path
- // To do that properly, we'll have to make the module directories
- // make dirs relative to workFile path before adding the paths to
- // the directory entries
-
workFile := modload.WorkFilePath()
if workFile == "" {
workFile = filepath.Join(base.Cwd(), "go.work")
func init() {
base.AddModCommonFlags(&cmdSync.Flag)
- base.AddWorkfileFlag(&cmdSync.Flag)
}
func runSync(ctx context.Context, cmd *base.Command, args []string) {
modload.ForceUseModules = true
modload.InitWorkfile()
if modload.WorkFilePath() == "" {
- base.Fatalf("go: no go.work file found\n\t(run 'go work init' first or specify path using -workfile flag)")
+ base.Fatalf("go: no go.work file found\n\t(run 'go work init' first or specify path using GOWORK environment variable)")
}
workGraph := modload.LoadModGraph(ctx, "")
cmdUse.Run = runUse // break init cycle
base.AddModCommonFlags(&cmdUse.Flag)
- base.AddWorkfileFlag(&cmdUse.Flag)
}
func runUse(ctx context.Context, cmd *base.Command, args []string) {
gowork = modload.WorkFilePath()
if gowork == "" {
- base.Fatalf("go: no go.work file found\n\t(run 'go work init' first or specify path using -workfile flag)")
+ base.Fatalf("go: no go.work file found\n\t(run 'go work init' first or specify path using GOWORK environment variable)")
}
workFile, err := modload.ReadWorkFile(gowork)
if err != nil {
go list -mod=readonly all
! go list -mod=mod all
stderr '^go: -mod may only be set to readonly when in workspace mode'
-go list -mod=mod -workfile=off all
+env GOWORK=off
+go list -mod=mod all
+env GOWORK=
# Test that duplicates in the use list return an error
cp go.work go.work.backup
# This exercises the code that determines which module command-line-arguments
# belongs to.
go list ./b/main.go
-go build -n -workfile=off -o foo foo.go
+env GOWORK=off
+go build -n -o foo foo.go
+env GOWORK=
go build -n -o foo foo.go
-- go.work.dup --
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
-go work edit -print -fmt -workfile $GOPATH/src/unformatted
+env GOWORK=$GOPATH/src/unformatted
+go work edit -print -fmt
cmp stdout formatted
-- m/go.mod --
go env GOWORK
stdout 'go.work'
+env GOWORK='off'
+go env GOWORK
+stdout 'off'
+
! go env -w GOWORK=off
stderr '^go: GOWORK cannot be modified$'
--- /dev/null
+env GOWORK=stop.work
+! go list a # require absolute path
+! stderr panic
+env GOWORK=doesnotexist
+! go list a
+! stderr panic
+
+env GOWORK=$GOPATH/src/stop.work
+go list -n a
+go build -n a
+go test -n a
+
+-- stop.work --
+go 1.18
+
+use ./a
+-- a/a.go --
+package a
+-- a/a_test.go --
+package a
+-- a/go.mod --
+module a
+
+go 1.18
\ No newline at end of file
-# Test that the workfile flag is used by go work init.
+# Test that the GOWORK environment variable flag is used by go work init.
+! exists go.work
go work init
exists go.work
-go work init -workfile=$GOPATH/src/foo/foo.work
+env GOWORK=$GOPATH/src/foo/foo.work
+! exists foo/foo.work
+go work init
exists foo/foo.work
+env GOWORK=
cd foo/bar
! go work init
stderr 'already exists'
! go work use
-stderr '^go: no go\.work file found\n\t\(run ''go work init'' first or specify path using -workfile flag\)$'
+stderr '^go: no go\.work file found\n\t\(run ''go work init'' first or specify path using GOWORK environment variable\)$'
! go work use .
-stderr '^go: no go\.work file found\n\t\(run ''go work init'' first or specify path using -workfile flag\)$'
+stderr '^go: no go\.work file found\n\t\(run ''go work init'' first or specify path using GOWORK environment variable\)$'
! go work edit
-stderr '^go: no go\.work file found\n\t\(run ''go work init'' first or specify path using -workfile flag\)$'
+stderr '^go: no go\.work file found\n\t\(run ''go work init'' first or specify path using GOWORK environment variable\)$'
! go work edit -go=1.18
-stderr '^go: no go\.work file found\n\t\(run ''go work init'' first or specify path using -workfile flag\)$'
+stderr '^go: no go\.work file found\n\t\(run ''go work init'' first or specify path using GOWORK environment variable\)$'
! go work sync
-stderr '^go: no go\.work file found\n\t\(run ''go work init'' first or specify path using -workfile flag\)$'
+stderr '^go: no go\.work file found\n\t\(run ''go work init'' first or specify path using GOWORK environment variable\)$'
-- go.mod --
module example
+++ /dev/null
-! go list -workfile=stop.work a # require absolute path
-! stderr panic
-! go list -workfile=doesnotexist a
-! stderr panic
-
-go list -n -workfile=$GOPATH/src/stop.work a
-go build -n -workfile=$GOPATH/src/stop.work a
-go test -n -workfile=$GOPATH/src/stop.work a
-
--- stop.work --
-go 1.18
-
-use ./a
--- a/a.go --
-package a
--- a/a_test.go --
-package a
--- a/go.mod --
-module a
-
-go 1.18
\ No newline at end of file
GOTOOLDIR
GOVCS
GOWASM
+ GOWORK
GO_EXTLINK_ENABLED
PKG_CONFIG
`