mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
all: REVERSE MERGE dev.cmdgo (220bc44) into master
This commit is a REVERSE MERGE. It merges dev.cmdgo back into its parent branch, master. This marks the end of development on dev.cmdgo. Merge List: + 2021-08-27220bc44a4c[dev.cmdgo] all: merge master (67f7e16) into dev.cmdgo + 2021-08-26de83ef67ac[dev.cmdgo] all: merge master (5e6a7e9) into dev.cmdgo + 2021-08-25de23549a39[dev.cmdgo] cmd/go: fix calls to modFileGoVersion to pass in modFile + 2021-08-253b523caf41[dev.cmdgo] cmd/go: clean up TODOWorkspaces instances + 2021-08-25109c13b64f[dev.cmdgo] all: merge master (c2f96e6) into dev.cmdgo + 2021-08-12e2e1987b31[dev.cmdgo] cmd/link: fix TestBuildForTvOS + 2021-08-12d397fc1169[dev.cmdgo] don't give command-line-arguments a module + 2021-08-11aaf914d0e6[dev.cmdgo] cmd/go: remove modload.ModRoot function + 2021-08-063025ce2fa8[dev.cmdgo] cmd/go: address code review comments in test cgo_path_space_quote + 2021-08-06fc8e0cbbba[dev.cmdgo] cmd: update x/tools and remove copy of txtar + 2021-07-313799012990[dev.cmdgo] cmd/go: add go mod editwork command + 2021-07-30b3b53e1dad[dev.cmdgo] cmd/go: thread through modroots providing replacements + 2021-07-3047694b59eb[dev.cmdgo] cmd/go: provide a more helpful missing required module error in workspaces + 2021-07-3090830699ae[dev.cmdgo] cmd/go: allow expliticly setting -mod=readonly in workspace mode + 2021-07-308e2ab05dd3Merge "[dev.cmdgo] all: merge master (9eee0ed) into dev.cmdgo" into dev.cmdgo + 2021-07-3052e970b1c8[dev.cmdgo] cmd: support space and quotes in CC and CXX + 2021-07-303a69cef65a[dev.cmdgo] cmd/internal/str: add utilities for quoting and splitting args + 2021-07-30137089ffb9[dev.cmdgo] cmd/internal/str: move package from cmd/go/internal/str + 2021-07-2847cdfa95ae[dev.cmdgo] all: merge master (9eee0ed) into dev.cmdgo + 2021-07-28176baafd5b[dev.cmdgo] cmd/go: sort roots when joining multiple main module roots + 2021-07-28288a83dcff[dev.cmdgo] cmd/go: maintain a go.work.sum file + 2021-07-272c8acf63c2[dev.cmdgo] cmd/go: make fewer 'go mod' commands update go.mod + 2021-07-2772233d27c4[dev.cmdgo] cmd/go: add -testsum flag to update go.sum in script tests + 2021-07-27b2205eab0e[dev.cmdgo] cmd/go: add go mod initwork command + 2021-07-27f05f5ceffa[dev.cmdgo] cmd/go: fold index and modFile into MainModules + 2021-07-267ce257147f[dev.cmdgo] cmd/go: add the workspace mode + 2021-07-263cd15e02ed[dev.cmdgo] cmd: pull in x/mod on the dev.cmdgo branch + 2021-07-22a627fcd3c4[dev.cmdgo] cmd/go: replace Target with MainModules, allowing for multiple targets + 2021-07-20ab361499ef[dev.cmdgo] cmd/go/testdata/script: fix a small typo in modfile_flag + 2021-07-06aa4da4f189[dev.cmdgo] all: merge master (912f075) into dev.cmdgo + 2020-12-226dc2c16f95[dev.cmdgo] codereview.cfg: add config for dev.cmdgo Change-Id: Ic42f1273e42c90954bd61a6e4d6ca193c97bf04c
This commit is contained in:
commit
acdea4f9f7
49 changed files with 2470 additions and 718 deletions
|
|
@ -7,7 +7,7 @@ require (
|
||||||
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639 // indirect
|
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639 // indirect
|
||||||
golang.org/x/arch v0.0.0-20210502124803-cbf565b21d1e
|
golang.org/x/arch v0.0.0-20210502124803-cbf565b21d1e
|
||||||
golang.org/x/crypto v0.0.0-20210503195802-e9a32991a82e // indirect
|
golang.org/x/crypto v0.0.0-20210503195802-e9a32991a82e // indirect
|
||||||
golang.org/x/mod v0.4.3-0.20210608190319-0f08993efd8a
|
golang.org/x/mod v0.4.3-0.20210723200715-e41a6a4f3b61
|
||||||
golang.org/x/sys v0.0.0-20210511113859-b0526f3d8744 // indirect
|
golang.org/x/sys v0.0.0-20210511113859-b0526f3d8744 // indirect
|
||||||
golang.org/x/term v0.0.0-20210503060354-a79de5458b56
|
golang.org/x/term v0.0.0-20210503060354-a79de5458b56
|
||||||
golang.org/x/tools v0.1.6-0.20210809225032-337cebd2c151
|
golang.org/x/tools v0.1.6-0.20210809225032-337cebd2c151
|
||||||
|
|
|
||||||
|
|
@ -9,8 +9,8 @@ golang.org/x/arch v0.0.0-20210502124803-cbf565b21d1e h1:pv3V0NlNSh5Q6AX/StwGLBjc
|
||||||
golang.org/x/arch v0.0.0-20210502124803-cbf565b21d1e/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
|
golang.org/x/arch v0.0.0-20210502124803-cbf565b21d1e/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
|
||||||
golang.org/x/crypto v0.0.0-20210503195802-e9a32991a82e h1:8foAy0aoO5GkqCvAEJ4VC4P3zksTg4X4aJCDpZzmgQI=
|
golang.org/x/crypto v0.0.0-20210503195802-e9a32991a82e h1:8foAy0aoO5GkqCvAEJ4VC4P3zksTg4X4aJCDpZzmgQI=
|
||||||
golang.org/x/crypto v0.0.0-20210503195802-e9a32991a82e/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8=
|
golang.org/x/crypto v0.0.0-20210503195802-e9a32991a82e/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8=
|
||||||
golang.org/x/mod v0.4.3-0.20210608190319-0f08993efd8a h1:e8qnjKz4EE6OjRki9wTadWSIogINvq10sMcuBRORxMY=
|
golang.org/x/mod v0.4.3-0.20210723200715-e41a6a4f3b61 h1:gQY3CVezomIImcWCpxp6Mhj+fXCOZ+gD8/88326LVqw=
|
||||||
golang.org/x/mod v0.4.3-0.20210608190319-0f08993efd8a/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
|
golang.org/x/mod v0.4.3-0.20210723200715-e41a6a4f3b61/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
|
||||||
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210511113859-b0526f3d8744 h1:yhBbb4IRs2HS9PPlAg6DMC6mUOKexJBNsLf4Z+6En1Q=
|
golang.org/x/sys v0.0.0-20210511113859-b0526f3d8744 h1:yhBbb4IRs2HS9PPlAg6DMC6mUOKexJBNsLf4Z+6En1Q=
|
||||||
golang.org/x/sys v0.0.0-20210511113859-b0526f3d8744/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210511113859-b0526f3d8744/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
|
|
||||||
|
|
@ -167,6 +167,14 @@
|
||||||
// directory, but it is not accessed. When -modfile is specified, an
|
// directory, but it is not accessed. When -modfile is specified, an
|
||||||
// alternate go.sum file is also used: its path is derived from the
|
// alternate go.sum file is also used: its path is derived from the
|
||||||
// -modfile flag by trimming the ".mod" extension and appending ".sum".
|
// -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
|
// -overlay file
|
||||||
// read a JSON config file that provides an overlay for build operations.
|
// 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
|
// The file is a JSON struct with a single field, named 'Replace', that
|
||||||
|
|
@ -1024,8 +1032,10 @@
|
||||||
//
|
//
|
||||||
// download download modules to local cache
|
// download download modules to local cache
|
||||||
// edit edit go.mod from tools or scripts
|
// edit edit go.mod from tools or scripts
|
||||||
|
// editwork edit go.work from tools or scripts
|
||||||
// graph print module requirement graph
|
// graph print module requirement graph
|
||||||
// init initialize new module in current directory
|
// init initialize new module in current directory
|
||||||
|
// initwork initialize workspace file
|
||||||
// tidy add missing and remove unused modules
|
// tidy add missing and remove unused modules
|
||||||
// vendor make vendored copy of dependencies
|
// vendor make vendored copy of dependencies
|
||||||
// verify verify dependencies have expected content
|
// verify verify dependencies have expected content
|
||||||
|
|
@ -1182,6 +1192,77 @@
|
||||||
// See https://golang.org/ref/mod#go-mod-edit for more about 'go mod edit'.
|
// See https://golang.org/ref/mod#go-mod-edit for more about 'go mod edit'.
|
||||||
//
|
//
|
||||||
//
|
//
|
||||||
|
// Edit go.work from tools or scripts
|
||||||
|
//
|
||||||
|
// Usage:
|
||||||
|
//
|
||||||
|
// go mod editwork [editing flags] [go.work]
|
||||||
|
//
|
||||||
|
// Editwork provides a command-line interface for editing go.work,
|
||||||
|
// for use primarily by tools or scripts. It only reads go.work;
|
||||||
|
// it does not look up information about the modules involved.
|
||||||
|
// If no file is specified, editwork looks for a go.work file in the current
|
||||||
|
// directory and its parent directories
|
||||||
|
//
|
||||||
|
// The editing flags specify a sequence of editing operations.
|
||||||
|
//
|
||||||
|
// The -fmt flag reformats the go.work file without making other changes.
|
||||||
|
// 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
|
||||||
|
// flags are specified, as in 'go mod editwork -fmt'.
|
||||||
|
//
|
||||||
|
// The -directory=path and -dropdirectory=path flags
|
||||||
|
// add and drop a directory from the go.work files set of module directories.
|
||||||
|
//
|
||||||
|
// The -replace=old[@v]=new[@v] flag adds a replacement of the given
|
||||||
|
// module path and version pair. If the @v in old@v is omitted, a
|
||||||
|
// replacement without a version on the left side is added, which applies
|
||||||
|
// to all versions of the old module path. If the @v in new@v is omitted,
|
||||||
|
// the new path should be a local module root directory, not a module
|
||||||
|
// path. Note that -replace overrides any redundant replacements for old[@v],
|
||||||
|
// so omitting @v will drop existing replacements for specific versions.
|
||||||
|
//
|
||||||
|
// The -dropreplace=old[@v] flag drops a replacement of the given
|
||||||
|
// module path and version pair. If the @v is omitted, a replacement without
|
||||||
|
// a version on the left side is dropped.
|
||||||
|
//
|
||||||
|
// The -directory, -dropdirectory, -replace, and -dropreplace,
|
||||||
|
// editing flags may be repeated, and the changes are applied in the order given.
|
||||||
|
//
|
||||||
|
// The -go=version flag sets the expected Go language version.
|
||||||
|
//
|
||||||
|
// The -print flag prints the final go.work in its text format instead of
|
||||||
|
// writing it back to go.mod.
|
||||||
|
//
|
||||||
|
// The -json flag prints the final go.work file in JSON format instead of
|
||||||
|
// writing it back to go.mod. The JSON output corresponds to these Go types:
|
||||||
|
//
|
||||||
|
// type Module struct {
|
||||||
|
// Path string
|
||||||
|
// Version string
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// type GoWork struct {
|
||||||
|
// Go string
|
||||||
|
// Directory []Directory
|
||||||
|
// Replace []Replace
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// type Directory struct {
|
||||||
|
// Path string
|
||||||
|
// ModulePath string
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// type Replace struct {
|
||||||
|
// Old Module
|
||||||
|
// New Module
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// See the workspaces design proposal at
|
||||||
|
// https://go.googlesource.com/proposal/+/master/design/45713-workspace.md for
|
||||||
|
// more information.
|
||||||
|
//
|
||||||
|
//
|
||||||
// Print module requirement graph
|
// Print module requirement graph
|
||||||
//
|
//
|
||||||
// Usage:
|
// Usage:
|
||||||
|
|
@ -1221,6 +1302,23 @@
|
||||||
// See https://golang.org/ref/mod#go-mod-init for more about 'go mod init'.
|
// See https://golang.org/ref/mod#go-mod-init for more about 'go mod init'.
|
||||||
//
|
//
|
||||||
//
|
//
|
||||||
|
// Initialize workspace file
|
||||||
|
//
|
||||||
|
// Usage:
|
||||||
|
//
|
||||||
|
// go mod initwork [moddirs]
|
||||||
|
//
|
||||||
|
// go mod initwork initializes and writes a new go.work file in the current
|
||||||
|
// directory, in effect creating a new workspace at the current directory.
|
||||||
|
//
|
||||||
|
// go mod initwork optionally accepts paths to the workspace modules as arguments.
|
||||||
|
// If the argument is omitted, an empty workspace with no modules will be created.
|
||||||
|
//
|
||||||
|
// See the workspaces design proposal at
|
||||||
|
// https://go.googlesource.com/proposal/+/master/design/45713-workspace.md for
|
||||||
|
// more information.
|
||||||
|
//
|
||||||
|
//
|
||||||
// Add missing and remove unused modules
|
// Add missing and remove unused modules
|
||||||
//
|
//
|
||||||
// Usage:
|
// Usage:
|
||||||
|
|
|
||||||
|
|
@ -62,6 +62,13 @@ func AddModFlag(flags *flag.FlagSet) {
|
||||||
flags.Var(explicitStringFlag{value: &cfg.BuildMod, explicit: &cfg.BuildModExplicit}, "mod", "")
|
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
|
// AddModCommonFlags adds the module-related flags common to build commands
|
||||||
// and 'go mod' subcommands.
|
// and 'go mod' subcommands.
|
||||||
func AddModCommonFlags(flags *flag.FlagSet) {
|
func AddModCommonFlags(flags *flag.FlagSet) {
|
||||||
|
|
|
||||||
|
|
@ -47,8 +47,10 @@ var (
|
||||||
BuildWork bool // -work flag
|
BuildWork bool // -work flag
|
||||||
BuildX bool // -x flag
|
BuildX bool // -x flag
|
||||||
|
|
||||||
ModCacheRW bool // -modcacherw flag
|
ModCacheRW bool // -modcacherw flag
|
||||||
ModFile string // -modfile flag
|
ModFile string // -modfile flag
|
||||||
|
WorkFile string // -workfile flag
|
||||||
|
WorkFileExplicit bool // whether -workfile was set explicitly
|
||||||
|
|
||||||
CmdName string // "build", "install", "list", "mod tidy", etc.
|
CmdName string // "build", "install", "list", "mod tidy", etc.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -146,8 +146,9 @@ func findEnv(env []cfg.EnvVar, name string) string {
|
||||||
// ExtraEnvVars returns environment variables that should not leak into child processes.
|
// ExtraEnvVars returns environment variables that should not leak into child processes.
|
||||||
func ExtraEnvVars() []cfg.EnvVar {
|
func ExtraEnvVars() []cfg.EnvVar {
|
||||||
gomod := ""
|
gomod := ""
|
||||||
|
modload.Init()
|
||||||
if modload.HasModRoot() {
|
if modload.HasModRoot() {
|
||||||
gomod = filepath.Join(modload.ModRoot(), "go.mod")
|
gomod = modload.ModFilePath()
|
||||||
} else if modload.Enabled() {
|
} else if modload.Enabled() {
|
||||||
gomod = os.DevNull
|
gomod = os.DevNull
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -225,7 +225,8 @@ func downloadPaths(patterns []string) []string {
|
||||||
base.ExitIfErrors()
|
base.ExitIfErrors()
|
||||||
|
|
||||||
var pkgs []string
|
var pkgs []string
|
||||||
for _, m := range search.ImportPathsQuiet(patterns) {
|
noModRoots := []string{}
|
||||||
|
for _, m := range search.ImportPathsQuiet(patterns, noModRoots) {
|
||||||
if len(m.Pkgs) == 0 && strings.Contains(m.Pattern(), "...") {
|
if len(m.Pkgs) == 0 && strings.Contains(m.Pattern(), "...") {
|
||||||
pkgs = append(pkgs, m.Pattern())
|
pkgs = append(pkgs, m.Pattern())
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -315,7 +316,8 @@ func download(arg string, parent *load.Package, stk *load.ImportStack, mode int)
|
||||||
if wildcardOkay && strings.Contains(arg, "...") {
|
if wildcardOkay && strings.Contains(arg, "...") {
|
||||||
match := search.NewMatch(arg)
|
match := search.NewMatch(arg)
|
||||||
if match.IsLocal() {
|
if match.IsLocal() {
|
||||||
match.MatchDirs()
|
noModRoots := []string{} // We're in gopath mode, so there are no modroots.
|
||||||
|
match.MatchDirs(noModRoots)
|
||||||
args = match.Dirs
|
args = match.Dirs
|
||||||
} else {
|
} else {
|
||||||
match.MatchPackages()
|
match.MatchPackages()
|
||||||
|
|
|
||||||
|
|
@ -316,6 +316,7 @@ For more about modules, see https://golang.org/ref/mod.
|
||||||
func init() {
|
func init() {
|
||||||
CmdList.Run = runList // break init cycle
|
CmdList.Run = runList // break init cycle
|
||||||
work.AddBuildFlags(CmdList, work.DefaultBuildFlags)
|
work.AddBuildFlags(CmdList, work.DefaultBuildFlags)
|
||||||
|
base.AddWorkfileFlag(&CmdList.Flag)
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|
@ -336,6 +337,8 @@ var (
|
||||||
var nl = []byte{'\n'}
|
var nl = []byte{'\n'}
|
||||||
|
|
||||||
func runList(ctx context.Context, cmd *base.Command, args []string) {
|
func runList(ctx context.Context, cmd *base.Command, args []string) {
|
||||||
|
modload.InitWorkfile()
|
||||||
|
|
||||||
if *listFmt != "" && *listJson == true {
|
if *listFmt != "" && *listJson == true {
|
||||||
base.Fatalf("go list -f cannot be used with -json")
|
base.Fatalf("go list -f cannot be used with -json")
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1450,9 +1450,9 @@ func disallowInternal(ctx context.Context, srcDir string, importer *Package, imp
|
||||||
// The importer is a list of command-line files.
|
// The importer is a list of command-line files.
|
||||||
// Pretend that the import path is the import path of the
|
// Pretend that the import path is the import path of the
|
||||||
// directory containing them.
|
// directory containing them.
|
||||||
// If the directory is outside the main module, this will resolve to ".",
|
// If the directory is outside the main modules, this will resolve to ".",
|
||||||
// which is not a prefix of any valid module.
|
// which is not a prefix of any valid module.
|
||||||
importerPath = modload.DirImportPath(ctx, importer.Dir)
|
importerPath, _ = modload.MainModules.DirImportPath(ctx, importer.Dir)
|
||||||
}
|
}
|
||||||
parentOfInternal := p.ImportPath[:i]
|
parentOfInternal := p.ImportPath[:i]
|
||||||
if str.HasPathPrefix(importerPath, parentOfInternal) {
|
if str.HasPathPrefix(importerPath, parentOfInternal) {
|
||||||
|
|
@ -2447,7 +2447,8 @@ func PackagesAndErrors(ctx context.Context, opts PackageOpts, patterns []string)
|
||||||
}
|
}
|
||||||
matches, _ = modload.LoadPackages(ctx, modOpts, patterns...)
|
matches, _ = modload.LoadPackages(ctx, modOpts, patterns...)
|
||||||
} else {
|
} else {
|
||||||
matches = search.ImportPaths(patterns)
|
noModRoots := []string{}
|
||||||
|
matches = search.ImportPaths(patterns, noModRoots)
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|
|
||||||
|
|
@ -66,6 +66,7 @@ func init() {
|
||||||
// TODO(jayconrod): https://golang.org/issue/35849 Apply -x to other 'go mod' commands.
|
// TODO(jayconrod): https://golang.org/issue/35849 Apply -x to other 'go mod' commands.
|
||||||
cmdDownload.Flag.BoolVar(&cfg.BuildX, "x", false, "")
|
cmdDownload.Flag.BoolVar(&cfg.BuildX, "x", false, "")
|
||||||
base.AddModCommonFlags(&cmdDownload.Flag)
|
base.AddModCommonFlags(&cmdDownload.Flag)
|
||||||
|
base.AddWorkfileFlag(&cmdDownload.Flag)
|
||||||
}
|
}
|
||||||
|
|
||||||
type moduleJSON struct {
|
type moduleJSON struct {
|
||||||
|
|
@ -81,6 +82,8 @@ type moduleJSON struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func runDownload(ctx context.Context, cmd *base.Command, args []string) {
|
func runDownload(ctx context.Context, cmd *base.Command, args []string) {
|
||||||
|
modload.InitWorkfile()
|
||||||
|
|
||||||
// Check whether modules are enabled and whether we're in a module.
|
// Check whether modules are enabled and whether we're in a module.
|
||||||
modload.ForceUseModules = true
|
modload.ForceUseModules = true
|
||||||
if !modload.HasModRoot() && len(args) == 0 {
|
if !modload.HasModRoot() && len(args) == 0 {
|
||||||
|
|
@ -91,12 +94,18 @@ func runDownload(ctx context.Context, cmd *base.Command, args []string) {
|
||||||
args = []string{"all"}
|
args = []string{"all"}
|
||||||
}
|
}
|
||||||
if modload.HasModRoot() {
|
if modload.HasModRoot() {
|
||||||
modload.LoadModFile(ctx) // to fill Target
|
modload.LoadModFile(ctx) // to fill MainModules
|
||||||
targetAtUpgrade := modload.Target.Path + "@upgrade"
|
|
||||||
targetAtPatch := modload.Target.Path + "@patch"
|
if len(modload.MainModules.Versions()) != 1 {
|
||||||
|
panic(modload.TODOWorkspaces("Support workspace mode in go mod download"))
|
||||||
|
}
|
||||||
|
mainModule := modload.MainModules.Versions()[0]
|
||||||
|
|
||||||
|
targetAtUpgrade := mainModule.Path + "@upgrade"
|
||||||
|
targetAtPatch := mainModule.Path + "@patch"
|
||||||
for _, arg := range args {
|
for _, arg := range args {
|
||||||
switch arg {
|
switch arg {
|
||||||
case modload.Target.Path, targetAtUpgrade, targetAtPatch:
|
case mainModule.Path, targetAtUpgrade, targetAtPatch:
|
||||||
os.Stderr.WriteString("go mod download: skipping argument " + arg + " that resolves to the main module\n")
|
os.Stderr.WriteString("go mod download: skipping argument " + arg + " that resolves to the main module\n")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
282
src/cmd/go/internal/modcmd/editwork.go
Normal file
282
src/cmd/go/internal/modcmd/editwork.go
Normal file
|
|
@ -0,0 +1,282 @@
|
||||||
|
// Copyright 2021 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// go mod editwork
|
||||||
|
|
||||||
|
package modcmd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"cmd/go/internal/base"
|
||||||
|
"cmd/go/internal/lockedfile"
|
||||||
|
"cmd/go/internal/modload"
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"golang.org/x/mod/modfile"
|
||||||
|
)
|
||||||
|
|
||||||
|
var cmdEditwork = &base.Command{
|
||||||
|
UsageLine: "go mod editwork [editing flags] [go.work]",
|
||||||
|
Short: "edit go.work from tools or scripts",
|
||||||
|
Long: `Editwork provides a command-line interface for editing go.work,
|
||||||
|
for use primarily by tools or scripts. It only reads go.work;
|
||||||
|
it does not look up information about the modules involved.
|
||||||
|
If no file is specified, editwork looks for a go.work file in the current
|
||||||
|
directory and its parent directories
|
||||||
|
|
||||||
|
The editing flags specify a sequence of editing operations.
|
||||||
|
|
||||||
|
The -fmt flag reformats the go.work file without making other changes.
|
||||||
|
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
|
||||||
|
flags are specified, as in 'go mod editwork -fmt'.
|
||||||
|
|
||||||
|
The -directory=path and -dropdirectory=path flags
|
||||||
|
add and drop a directory from the go.work files set of module directories.
|
||||||
|
|
||||||
|
The -replace=old[@v]=new[@v] flag adds a replacement of the given
|
||||||
|
module path and version pair. If the @v in old@v is omitted, a
|
||||||
|
replacement without a version on the left side is added, which applies
|
||||||
|
to all versions of the old module path. If the @v in new@v is omitted,
|
||||||
|
the new path should be a local module root directory, not a module
|
||||||
|
path. Note that -replace overrides any redundant replacements for old[@v],
|
||||||
|
so omitting @v will drop existing replacements for specific versions.
|
||||||
|
|
||||||
|
The -dropreplace=old[@v] flag drops a replacement of the given
|
||||||
|
module path and version pair. If the @v is omitted, a replacement without
|
||||||
|
a version on the left side is dropped.
|
||||||
|
|
||||||
|
The -directory, -dropdirectory, -replace, and -dropreplace,
|
||||||
|
editing flags may be repeated, and the changes are applied in the order given.
|
||||||
|
|
||||||
|
The -go=version flag sets the expected Go language version.
|
||||||
|
|
||||||
|
The -print flag prints the final go.work in its text format instead of
|
||||||
|
writing it back to go.mod.
|
||||||
|
|
||||||
|
The -json flag prints the final go.work file in JSON format instead of
|
||||||
|
writing it back to go.mod. The JSON output corresponds to these Go types:
|
||||||
|
|
||||||
|
type Module struct {
|
||||||
|
Path string
|
||||||
|
Version string
|
||||||
|
}
|
||||||
|
|
||||||
|
type GoWork struct {
|
||||||
|
Go string
|
||||||
|
Directory []Directory
|
||||||
|
Replace []Replace
|
||||||
|
}
|
||||||
|
|
||||||
|
type Directory struct {
|
||||||
|
Path string
|
||||||
|
ModulePath string
|
||||||
|
}
|
||||||
|
|
||||||
|
type Replace struct {
|
||||||
|
Old Module
|
||||||
|
New Module
|
||||||
|
}
|
||||||
|
|
||||||
|
See the workspaces design proposal at
|
||||||
|
https://go.googlesource.com/proposal/+/master/design/45713-workspace.md for
|
||||||
|
more information.
|
||||||
|
`,
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
editworkFmt = cmdEditwork.Flag.Bool("fmt", false, "")
|
||||||
|
editworkGo = cmdEditwork.Flag.String("go", "", "")
|
||||||
|
editworkJSON = cmdEditwork.Flag.Bool("json", false, "")
|
||||||
|
editworkPrint = cmdEditwork.Flag.Bool("print", false, "")
|
||||||
|
workedits []func(file *modfile.WorkFile) // edits specified in flags
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
cmdEditwork.Run = runEditwork // break init cycle
|
||||||
|
|
||||||
|
cmdEditwork.Flag.Var(flagFunc(flagEditworkDirectory), "directory", "")
|
||||||
|
cmdEditwork.Flag.Var(flagFunc(flagEditworkDropDirectory), "dropdirectory", "")
|
||||||
|
cmdEditwork.Flag.Var(flagFunc(flagEditworkReplace), "replace", "")
|
||||||
|
cmdEditwork.Flag.Var(flagFunc(flagEditworkDropReplace), "dropreplace", "")
|
||||||
|
|
||||||
|
base.AddWorkfileFlag(&cmdEditwork.Flag)
|
||||||
|
}
|
||||||
|
|
||||||
|
func runEditwork(ctx context.Context, cmd *base.Command, args []string) {
|
||||||
|
anyFlags :=
|
||||||
|
*editworkGo != "" ||
|
||||||
|
*editworkJSON ||
|
||||||
|
*editworkPrint ||
|
||||||
|
*editworkFmt ||
|
||||||
|
len(workedits) > 0
|
||||||
|
|
||||||
|
if !anyFlags {
|
||||||
|
base.Fatalf("go mod edit: no flags specified (see 'go help mod edit').")
|
||||||
|
}
|
||||||
|
|
||||||
|
if *editworkJSON && *editworkPrint {
|
||||||
|
base.Fatalf("go mod edit: cannot use both -json and -print")
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(args) > 1 {
|
||||||
|
base.Fatalf("go mod edit: too many arguments")
|
||||||
|
}
|
||||||
|
var gowork string
|
||||||
|
if len(args) == 1 {
|
||||||
|
gowork = args[0]
|
||||||
|
} else {
|
||||||
|
modload.InitWorkfile()
|
||||||
|
gowork = modload.WorkFilePath()
|
||||||
|
}
|
||||||
|
|
||||||
|
if *editworkGo != "" {
|
||||||
|
if !modfile.GoVersionRE.MatchString(*editworkGo) {
|
||||||
|
base.Fatalf(`go mod: invalid -go option; expecting something like "-go %s"`, modload.LatestGoVersion())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
data, err := lockedfile.Read(gowork)
|
||||||
|
if err != nil {
|
||||||
|
base.Fatalf("go: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
workFile, err := modfile.ParseWork(gowork, data, nil)
|
||||||
|
if err != nil {
|
||||||
|
base.Fatalf("go: errors parsing %s:\n%s", base.ShortPath(gowork), err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if *editworkGo != "" {
|
||||||
|
if err := workFile.AddGoStmt(*editworkGo); err != nil {
|
||||||
|
base.Fatalf("go: internal error: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(workedits) > 0 {
|
||||||
|
for _, edit := range workedits {
|
||||||
|
edit(workFile)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
workFile.SortBlocks()
|
||||||
|
workFile.Cleanup() // clean file after edits
|
||||||
|
|
||||||
|
if *editworkJSON {
|
||||||
|
editworkPrintJSON(workFile)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
out := modfile.Format(workFile.Syntax)
|
||||||
|
|
||||||
|
if *editworkPrint {
|
||||||
|
os.Stdout.Write(out)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = lockedfile.Transform(gowork, func(lockedData []byte) ([]byte, error) {
|
||||||
|
if !bytes.Equal(lockedData, data) {
|
||||||
|
return nil, errors.New("go.work changed during editing; not overwriting")
|
||||||
|
}
|
||||||
|
return out, nil
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
base.Fatalf("go: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// flagEditworkDirectory implements the -directory flag.
|
||||||
|
func flagEditworkDirectory(arg string) {
|
||||||
|
workedits = append(workedits, func(f *modfile.WorkFile) {
|
||||||
|
if err := f.AddDirectory(arg, ""); err != nil {
|
||||||
|
base.Fatalf("go mod: -directory=%s: %v", arg, err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// flagEditworkDropDirectory implements the -dropdirectory flag.
|
||||||
|
func flagEditworkDropDirectory(arg string) {
|
||||||
|
workedits = append(workedits, func(f *modfile.WorkFile) {
|
||||||
|
if err := f.DropDirectory(arg); err != nil {
|
||||||
|
base.Fatalf("go mod: -dropdirectory=%s: %v", arg, err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// flagReplace implements the -replace flag.
|
||||||
|
func flagEditworkReplace(arg string) {
|
||||||
|
var i int
|
||||||
|
if i = strings.Index(arg, "="); i < 0 {
|
||||||
|
base.Fatalf("go mod: -replace=%s: need old[@v]=new[@w] (missing =)", arg)
|
||||||
|
}
|
||||||
|
old, new := strings.TrimSpace(arg[:i]), strings.TrimSpace(arg[i+1:])
|
||||||
|
if strings.HasPrefix(new, ">") {
|
||||||
|
base.Fatalf("go mod: -replace=%s: separator between old and new is =, not =>", arg)
|
||||||
|
}
|
||||||
|
oldPath, oldVersion, err := parsePathVersionOptional("old", old, false)
|
||||||
|
if err != nil {
|
||||||
|
base.Fatalf("go mod: -replace=%s: %v", arg, err)
|
||||||
|
}
|
||||||
|
newPath, newVersion, err := parsePathVersionOptional("new", new, true)
|
||||||
|
if err != nil {
|
||||||
|
base.Fatalf("go mod: -replace=%s: %v", arg, err)
|
||||||
|
}
|
||||||
|
if newPath == new && !modfile.IsDirectoryPath(new) {
|
||||||
|
base.Fatalf("go mod: -replace=%s: unversioned new path must be local directory", arg)
|
||||||
|
}
|
||||||
|
|
||||||
|
workedits = append(workedits, func(f *modfile.WorkFile) {
|
||||||
|
if err := f.AddReplace(oldPath, oldVersion, newPath, newVersion); err != nil {
|
||||||
|
base.Fatalf("go mod: -replace=%s: %v", arg, err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// flagDropReplace implements the -dropreplace flag.
|
||||||
|
func flagEditworkDropReplace(arg string) {
|
||||||
|
path, version, err := parsePathVersionOptional("old", arg, true)
|
||||||
|
if err != nil {
|
||||||
|
base.Fatalf("go mod: -dropreplace=%s: %v", arg, err)
|
||||||
|
}
|
||||||
|
workedits = append(workedits, func(f *modfile.WorkFile) {
|
||||||
|
if err := f.DropReplace(path, version); err != nil {
|
||||||
|
base.Fatalf("go mod: -dropreplace=%s: %v", arg, err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// editPrintJSON prints the -json output.
|
||||||
|
func editworkPrintJSON(workFile *modfile.WorkFile) {
|
||||||
|
var f workfileJSON
|
||||||
|
if workFile.Go != nil {
|
||||||
|
f.Go = workFile.Go.Version
|
||||||
|
}
|
||||||
|
for _, d := range workFile.Directory {
|
||||||
|
f.Directory = append(f.Directory, directoryJSON{DiskPath: d.Path, ModPath: d.ModulePath})
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, r := range workFile.Replace {
|
||||||
|
f.Replace = append(f.Replace, replaceJSON{r.Old, r.New})
|
||||||
|
}
|
||||||
|
data, err := json.MarshalIndent(&f, "", "\t")
|
||||||
|
if err != nil {
|
||||||
|
base.Fatalf("go: internal error: %v", err)
|
||||||
|
}
|
||||||
|
data = append(data, '\n')
|
||||||
|
os.Stdout.Write(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
// workfileJSON is the -json output data structure.
|
||||||
|
type workfileJSON struct {
|
||||||
|
Go string `json:",omitempty"`
|
||||||
|
Directory []directoryJSON
|
||||||
|
Replace []replaceJSON
|
||||||
|
}
|
||||||
|
|
||||||
|
type directoryJSON struct {
|
||||||
|
DiskPath string
|
||||||
|
ModPath string `json:",omitempty"`
|
||||||
|
}
|
||||||
|
|
@ -42,9 +42,12 @@ var (
|
||||||
func init() {
|
func init() {
|
||||||
cmdGraph.Flag.Var(&graphGo, "go", "")
|
cmdGraph.Flag.Var(&graphGo, "go", "")
|
||||||
base.AddModCommonFlags(&cmdGraph.Flag)
|
base.AddModCommonFlags(&cmdGraph.Flag)
|
||||||
|
base.AddWorkfileFlag(&cmdGraph.Flag)
|
||||||
}
|
}
|
||||||
|
|
||||||
func runGraph(ctx context.Context, cmd *base.Command, args []string) {
|
func runGraph(ctx context.Context, cmd *base.Command, args []string) {
|
||||||
|
modload.InitWorkfile()
|
||||||
|
|
||||||
if len(args) > 0 {
|
if len(args) > 0 {
|
||||||
base.Fatalf("go mod graph: graph takes no arguments")
|
base.Fatalf("go mod graph: graph takes no arguments")
|
||||||
}
|
}
|
||||||
|
|
|
||||||
54
src/cmd/go/internal/modcmd/initwork.go
Normal file
54
src/cmd/go/internal/modcmd/initwork.go
Normal file
|
|
@ -0,0 +1,54 @@
|
||||||
|
// Copyright 2021 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// go mod initwork
|
||||||
|
|
||||||
|
package modcmd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"cmd/go/internal/base"
|
||||||
|
"cmd/go/internal/modload"
|
||||||
|
"context"
|
||||||
|
"path/filepath"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ = modload.TODOWorkspaces("Add more documentation below. Though this is" +
|
||||||
|
"enough for those trying workspaces out, there should be more through" +
|
||||||
|
"documentation if the proposal is accepted and released.")
|
||||||
|
|
||||||
|
var cmdInitwork = &base.Command{
|
||||||
|
UsageLine: "go mod initwork [moddirs]",
|
||||||
|
Short: "initialize workspace file",
|
||||||
|
Long: `go mod initwork initializes and writes a new go.work file in the current
|
||||||
|
directory, in effect creating a new workspace at the current directory.
|
||||||
|
|
||||||
|
go mod initwork optionally accepts paths to the workspace modules as arguments.
|
||||||
|
If the argument is omitted, an empty workspace with no modules will be created.
|
||||||
|
|
||||||
|
See the workspaces design proposal at
|
||||||
|
https://go.googlesource.com/proposal/+/master/design/45713-workspace.md for
|
||||||
|
more information.
|
||||||
|
`,
|
||||||
|
Run: runInitwork,
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
base.AddModCommonFlags(&cmdInitwork.Flag)
|
||||||
|
base.AddWorkfileFlag(&cmdInitwork.Flag)
|
||||||
|
}
|
||||||
|
|
||||||
|
func runInitwork(ctx context.Context, cmd *base.Command, args []string) {
|
||||||
|
modload.InitWorkfile()
|
||||||
|
|
||||||
|
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 := filepath.Join(base.Cwd(), "go.work")
|
||||||
|
|
||||||
|
modload.CreateWorkFile(ctx, workFile, args)
|
||||||
|
}
|
||||||
|
|
@ -23,8 +23,10 @@ See 'go help modules' for an overview of module functionality.
|
||||||
Commands: []*base.Command{
|
Commands: []*base.Command{
|
||||||
cmdDownload,
|
cmdDownload,
|
||||||
cmdEdit,
|
cmdEdit,
|
||||||
|
cmdEditwork,
|
||||||
cmdGraph,
|
cmdGraph,
|
||||||
cmdInit,
|
cmdInit,
|
||||||
|
cmdInitwork,
|
||||||
cmdTidy,
|
cmdTidy,
|
||||||
cmdVendor,
|
cmdVendor,
|
||||||
cmdVerify,
|
cmdVerify,
|
||||||
|
|
|
||||||
|
|
@ -74,7 +74,7 @@ func runVendor(ctx context.Context, cmd *base.Command, args []string) {
|
||||||
}
|
}
|
||||||
_, pkgs := modload.LoadPackages(ctx, loadOpts, "all")
|
_, pkgs := modload.LoadPackages(ctx, loadOpts, "all")
|
||||||
|
|
||||||
vdir := filepath.Join(modload.ModRoot(), "vendor")
|
vdir := filepath.Join(modload.VendorDir())
|
||||||
if err := os.RemoveAll(vdir); err != nil {
|
if err := os.RemoveAll(vdir); err != nil {
|
||||||
base.Fatalf("go mod vendor: %v", err)
|
base.Fatalf("go mod vendor: %v", err)
|
||||||
}
|
}
|
||||||
|
|
@ -82,7 +82,7 @@ func runVendor(ctx context.Context, cmd *base.Command, args []string) {
|
||||||
modpkgs := make(map[module.Version][]string)
|
modpkgs := make(map[module.Version][]string)
|
||||||
for _, pkg := range pkgs {
|
for _, pkg := range pkgs {
|
||||||
m := modload.PackageModule(pkg)
|
m := modload.PackageModule(pkg)
|
||||||
if m.Path == "" || m == modload.Target {
|
if m.Path == "" || m.Version == "" && modload.MainModules.Contains(m.Path) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
modpkgs[m] = append(modpkgs[m], pkg)
|
modpkgs[m] = append(modpkgs[m], pkg)
|
||||||
|
|
@ -128,7 +128,8 @@ func runVendor(ctx context.Context, cmd *base.Command, args []string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, m := range vendorMods {
|
for _, m := range vendorMods {
|
||||||
line := moduleLine(m, modload.Replacement(m))
|
replacement, _ := modload.Replacement(m)
|
||||||
|
line := moduleLine(m, replacement)
|
||||||
io.WriteString(w, line)
|
io.WriteString(w, line)
|
||||||
|
|
||||||
goVersion := ""
|
goVersion := ""
|
||||||
|
|
|
||||||
|
|
@ -39,9 +39,12 @@ See https://golang.org/ref/mod#go-mod-verify for more about 'go mod verify'.
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
base.AddModCommonFlags(&cmdVerify.Flag)
|
base.AddModCommonFlags(&cmdVerify.Flag)
|
||||||
|
base.AddWorkfileFlag(&cmdVerify.Flag)
|
||||||
}
|
}
|
||||||
|
|
||||||
func runVerify(ctx context.Context, cmd *base.Command, args []string) {
|
func runVerify(ctx context.Context, cmd *base.Command, args []string) {
|
||||||
|
modload.InitWorkfile()
|
||||||
|
|
||||||
if len(args) != 0 {
|
if len(args) != 0 {
|
||||||
// NOTE(rsc): Could take a module pattern.
|
// NOTE(rsc): Could take a module pattern.
|
||||||
base.Fatalf("go mod verify: verify takes no arguments")
|
base.Fatalf("go mod verify: verify takes no arguments")
|
||||||
|
|
|
||||||
|
|
@ -61,9 +61,11 @@ var (
|
||||||
func init() {
|
func init() {
|
||||||
cmdWhy.Run = runWhy // break init cycle
|
cmdWhy.Run = runWhy // break init cycle
|
||||||
base.AddModCommonFlags(&cmdWhy.Flag)
|
base.AddModCommonFlags(&cmdWhy.Flag)
|
||||||
|
base.AddWorkfileFlag(&cmdWhy.Flag)
|
||||||
}
|
}
|
||||||
|
|
||||||
func runWhy(ctx context.Context, cmd *base.Command, args []string) {
|
func runWhy(ctx context.Context, cmd *base.Command, args []string) {
|
||||||
|
modload.InitWorkfile()
|
||||||
modload.ForceUseModules = true
|
modload.ForceUseModules = true
|
||||||
modload.RootMode = modload.NeedRoot
|
modload.RootMode = modload.NeedRoot
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -693,19 +693,21 @@ func isValidSum(data []byte) bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var ErrGoSumDirty = errors.New("updates to go.sum needed, disabled by -mod=readonly")
|
||||||
|
|
||||||
// WriteGoSum writes the go.sum file if it needs to be updated.
|
// WriteGoSum writes the go.sum file if it needs to be updated.
|
||||||
//
|
//
|
||||||
// keep is used to check whether a newly added sum should be saved in go.sum.
|
// keep is used to check whether a newly added sum should be saved in go.sum.
|
||||||
// It should have entries for both module content sums and go.mod sums
|
// It should have entries for both module content sums and go.mod sums
|
||||||
// (version ends with "/go.mod"). Existing sums will be preserved unless they
|
// (version ends with "/go.mod"). Existing sums will be preserved unless they
|
||||||
// have been marked for deletion with TrimGoSum.
|
// have been marked for deletion with TrimGoSum.
|
||||||
func WriteGoSum(keep map[module.Version]bool) {
|
func WriteGoSum(keep map[module.Version]bool, readonly bool) error {
|
||||||
goSum.mu.Lock()
|
goSum.mu.Lock()
|
||||||
defer goSum.mu.Unlock()
|
defer goSum.mu.Unlock()
|
||||||
|
|
||||||
// If we haven't read the go.sum file yet, don't bother writing it.
|
// If we haven't read the go.sum file yet, don't bother writing it.
|
||||||
if !goSum.enabled {
|
if !goSum.enabled {
|
||||||
return
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check whether we need to add sums for which keep[m] is true or remove
|
// Check whether we need to add sums for which keep[m] is true or remove
|
||||||
|
|
@ -723,10 +725,10 @@ Outer:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !dirty {
|
if !dirty {
|
||||||
return
|
return nil
|
||||||
}
|
}
|
||||||
if cfg.BuildMod == "readonly" {
|
if readonly {
|
||||||
base.Fatalf("go: updates to go.sum needed, disabled by -mod=readonly")
|
return ErrGoSumDirty
|
||||||
}
|
}
|
||||||
if _, ok := fsys.OverlayPath(GoSumFile); ok {
|
if _, ok := fsys.OverlayPath(GoSumFile); ok {
|
||||||
base.Fatalf("go: updates to go.sum needed, but go.sum is part of the overlay specified with -overlay")
|
base.Fatalf("go: updates to go.sum needed, but go.sum is part of the overlay specified with -overlay")
|
||||||
|
|
@ -774,11 +776,12 @@ Outer:
|
||||||
})
|
})
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
base.Fatalf("go: updating go.sum: %v", err)
|
return fmt.Errorf("updating go.sum: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
goSum.status = make(map[modSum]modSumStatus)
|
goSum.status = make(map[modSum]modSumStatus)
|
||||||
goSum.overwrite = false
|
goSum.overwrite = false
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// TrimGoSum trims go.sum to contain only the modules needed for reproducible
|
// TrimGoSum trims go.sum to contain only the modules needed for reproducible
|
||||||
|
|
|
||||||
|
|
@ -389,9 +389,11 @@ func runGet(ctx context.Context, cmd *base.Command, args []string) {
|
||||||
|
|
||||||
haveExternalExe := false
|
haveExternalExe := false
|
||||||
for _, pkg := range pkgs {
|
for _, pkg := range pkgs {
|
||||||
if pkg.Name == "main" && pkg.Module != nil && pkg.Module.Path != modload.Target.Path {
|
if pkg.Name == "main" && pkg.Module != nil {
|
||||||
haveExternalExe = true
|
if !modload.MainModules.Contains(pkg.Module.Path) {
|
||||||
break
|
haveExternalExe = true
|
||||||
|
break
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if haveExternalExe {
|
if haveExternalExe {
|
||||||
|
|
@ -675,7 +677,9 @@ func (r *resolver) queryNone(ctx context.Context, q *query) {
|
||||||
|
|
||||||
if !q.isWildcard() {
|
if !q.isWildcard() {
|
||||||
q.pathOnce(q.pattern, func() pathSet {
|
q.pathOnce(q.pattern, func() pathSet {
|
||||||
if modload.HasModRoot() && q.pattern == modload.Target.Path {
|
hasModRoot := modload.HasModRoot()
|
||||||
|
if hasModRoot && modload.MainModules.Contains(q.pattern) {
|
||||||
|
v := module.Version{Path: q.pattern}
|
||||||
// The user has explicitly requested to downgrade their own module to
|
// The user has explicitly requested to downgrade their own module to
|
||||||
// version "none". This is not an entirely unreasonable request: it
|
// version "none". This is not an entirely unreasonable request: it
|
||||||
// could plausibly mean “downgrade away everything that depends on any
|
// could plausibly mean “downgrade away everything that depends on any
|
||||||
|
|
@ -686,7 +690,7 @@ func (r *resolver) queryNone(ctx context.Context, q *query) {
|
||||||
// However, neither of those behaviors would be consistent with the
|
// However, neither of those behaviors would be consistent with the
|
||||||
// plain meaning of the query. To try to reduce confusion, reject the
|
// plain meaning of the query. To try to reduce confusion, reject the
|
||||||
// query explicitly.
|
// query explicitly.
|
||||||
return errSet(&modload.QueryMatchesMainModuleError{Pattern: q.pattern, Query: q.version})
|
return errSet(&modload.QueryMatchesMainModulesError{MainModules: []module.Version{v}, Pattern: q.pattern, Query: q.version})
|
||||||
}
|
}
|
||||||
|
|
||||||
return pathSet{mod: module.Version{Path: q.pattern, Version: "none"}}
|
return pathSet{mod: module.Version{Path: q.pattern, Version: "none"}}
|
||||||
|
|
@ -698,8 +702,8 @@ func (r *resolver) queryNone(ctx context.Context, q *query) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
q.pathOnce(curM.Path, func() pathSet {
|
q.pathOnce(curM.Path, func() pathSet {
|
||||||
if modload.HasModRoot() && curM == modload.Target {
|
if modload.HasModRoot() && curM.Version == "" && modload.MainModules.Contains(curM.Path) {
|
||||||
return errSet(&modload.QueryMatchesMainModuleError{Pattern: q.pattern, Query: q.version})
|
return errSet(&modload.QueryMatchesMainModulesError{MainModules: []module.Version{curM}, Pattern: q.pattern, Query: q.version})
|
||||||
}
|
}
|
||||||
return pathSet{mod: module.Version{Path: curM.Path, Version: "none"}}
|
return pathSet{mod: module.Version{Path: curM.Path, Version: "none"}}
|
||||||
})
|
})
|
||||||
|
|
@ -718,12 +722,21 @@ func (r *resolver) performLocalQueries(ctx context.Context) {
|
||||||
|
|
||||||
// Absolute paths like C:\foo and relative paths like ../foo... are
|
// Absolute paths like C:\foo and relative paths like ../foo... are
|
||||||
// restricted to matching packages in the main module.
|
// restricted to matching packages in the main module.
|
||||||
pkgPattern := modload.DirImportPath(ctx, q.pattern)
|
pkgPattern, mainModule := modload.MainModules.DirImportPath(ctx, q.pattern)
|
||||||
if pkgPattern == "." {
|
if pkgPattern == "." {
|
||||||
return errSet(fmt.Errorf("%s%s is not within module rooted at %s", q.pattern, absDetail, modload.ModRoot()))
|
modload.MustHaveModRoot()
|
||||||
|
var modRoots []string
|
||||||
|
for _, m := range modload.MainModules.Versions() {
|
||||||
|
modRoots = append(modRoots, modload.MainModules.ModRoot(m))
|
||||||
|
}
|
||||||
|
var plural string
|
||||||
|
if len(modRoots) != 1 {
|
||||||
|
plural = "s"
|
||||||
|
}
|
||||||
|
return errSet(fmt.Errorf("%s%s is not within module%s rooted at %s", q.pattern, absDetail, plural, strings.Join(modRoots, ", ")))
|
||||||
}
|
}
|
||||||
|
|
||||||
match := modload.MatchInModule(ctx, pkgPattern, modload.Target, imports.AnyTags())
|
match := modload.MatchInModule(ctx, pkgPattern, mainModule, imports.AnyTags())
|
||||||
if len(match.Errs) > 0 {
|
if len(match.Errs) > 0 {
|
||||||
return pathSet{err: match.Errs[0]}
|
return pathSet{err: match.Errs[0]}
|
||||||
}
|
}
|
||||||
|
|
@ -733,13 +746,14 @@ func (r *resolver) performLocalQueries(ctx context.Context) {
|
||||||
return errSet(fmt.Errorf("no package in current directory"))
|
return errSet(fmt.Errorf("no package in current directory"))
|
||||||
}
|
}
|
||||||
if !q.isWildcard() {
|
if !q.isWildcard() {
|
||||||
return errSet(fmt.Errorf("%s%s is not a package in module rooted at %s", q.pattern, absDetail, modload.ModRoot()))
|
modload.MustHaveModRoot()
|
||||||
|
return errSet(fmt.Errorf("%s%s is not a package in module rooted at %s", q.pattern, absDetail, modload.MainModules.ModRoot(mainModule)))
|
||||||
}
|
}
|
||||||
search.WarnUnmatched([]*search.Match{match})
|
search.WarnUnmatched([]*search.Match{match})
|
||||||
return pathSet{}
|
return pathSet{}
|
||||||
}
|
}
|
||||||
|
|
||||||
return pathSet{pkgMods: []module.Version{modload.Target}}
|
return pathSet{pkgMods: []module.Version{mainModule}}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -789,11 +803,12 @@ func (r *resolver) queryWildcard(ctx context.Context, q *query) {
|
||||||
return pathSet{}
|
return pathSet{}
|
||||||
}
|
}
|
||||||
|
|
||||||
if curM.Path == modload.Target.Path && !versionOkForMainModule(q.version) {
|
if modload.MainModules.Contains(curM.Path) && !versionOkForMainModule(q.version) {
|
||||||
if q.matchesPath(curM.Path) {
|
if q.matchesPath(curM.Path) {
|
||||||
return errSet(&modload.QueryMatchesMainModuleError{
|
return errSet(&modload.QueryMatchesMainModulesError{
|
||||||
Pattern: q.pattern,
|
MainModules: []module.Version{curM},
|
||||||
Query: q.version,
|
Pattern: q.pattern,
|
||||||
|
Query: q.version,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1159,8 +1174,8 @@ func (r *resolver) loadPackages(ctx context.Context, patterns []string, findPack
|
||||||
}
|
}
|
||||||
|
|
||||||
opts.AllowPackage = func(ctx context.Context, path string, m module.Version) error {
|
opts.AllowPackage = func(ctx context.Context, path string, m module.Version) error {
|
||||||
if m.Path == "" || m == modload.Target {
|
if m.Path == "" || m.Version == "" && modload.MainModules.Contains(m.Path) {
|
||||||
// Packages in the standard library and main module are already at their
|
// Packages in the standard library and main modules are already at their
|
||||||
// latest (and only) available versions.
|
// latest (and only) available versions.
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
@ -1370,11 +1385,11 @@ func (r *resolver) disambiguate(cs pathSet) (filtered pathSet, isPackage bool, m
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if m.Path == modload.Target.Path {
|
if modload.MainModules.Contains(m.Path) {
|
||||||
if m.Version == modload.Target.Version {
|
if m.Version == "" {
|
||||||
return pathSet{}, true, m, true
|
return pathSet{}, true, m, true
|
||||||
}
|
}
|
||||||
// The main module can only be set to its own version.
|
// A main module can only be set to its own version.
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1610,7 +1625,7 @@ func (r *resolver) checkPackageProblems(ctx context.Context, pkgPatterns []strin
|
||||||
i := i
|
i := i
|
||||||
m := r.buildList[i]
|
m := r.buildList[i]
|
||||||
mActual := m
|
mActual := m
|
||||||
if mRepl := modload.Replacement(m); mRepl.Path != "" {
|
if mRepl, _ := modload.Replacement(m); mRepl.Path != "" {
|
||||||
mActual = mRepl
|
mActual = mRepl
|
||||||
}
|
}
|
||||||
old := module.Version{Path: m.Path, Version: r.initialVersion[m.Path]}
|
old := module.Version{Path: m.Path, Version: r.initialVersion[m.Path]}
|
||||||
|
|
@ -1618,7 +1633,7 @@ func (r *resolver) checkPackageProblems(ctx context.Context, pkgPatterns []strin
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
oldActual := old
|
oldActual := old
|
||||||
if oldRepl := modload.Replacement(old); oldRepl.Path != "" {
|
if oldRepl, _ := modload.Replacement(old); oldRepl.Path != "" {
|
||||||
oldActual = oldRepl
|
oldActual = oldRepl
|
||||||
}
|
}
|
||||||
if mActual == oldActual || mActual.Version == "" || !modfetch.HaveSum(oldActual) {
|
if mActual == oldActual || mActual.Version == "" || !modfetch.HaveSum(oldActual) {
|
||||||
|
|
@ -1744,10 +1759,11 @@ func (r *resolver) resolve(q *query, m module.Version) {
|
||||||
panic("internal error: resolving a module.Version with an empty path")
|
panic("internal error: resolving a module.Version with an empty path")
|
||||||
}
|
}
|
||||||
|
|
||||||
if m.Path == modload.Target.Path && m.Version != modload.Target.Version {
|
if modload.MainModules.Contains(m.Path) && m.Version != "" {
|
||||||
reportError(q, &modload.QueryMatchesMainModuleError{
|
reportError(q, &modload.QueryMatchesMainModulesError{
|
||||||
Pattern: q.pattern,
|
MainModules: []module.Version{{Path: m.Path}},
|
||||||
Query: q.version,
|
Pattern: q.pattern,
|
||||||
|
Query: q.version,
|
||||||
})
|
})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
@ -1775,7 +1791,7 @@ func (r *resolver) updateBuildList(ctx context.Context, additions []module.Versi
|
||||||
|
|
||||||
resolved := make([]module.Version, 0, len(r.resolvedVersion))
|
resolved := make([]module.Version, 0, len(r.resolvedVersion))
|
||||||
for mPath, rv := range r.resolvedVersion {
|
for mPath, rv := range r.resolvedVersion {
|
||||||
if mPath != modload.Target.Path {
|
if !modload.MainModules.Contains(mPath) {
|
||||||
resolved = append(resolved, module.Version{Path: mPath, Version: rv.version})
|
resolved = append(resolved, module.Version{Path: mPath, Version: rv.version})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -192,9 +192,9 @@ func (q *query) validate() error {
|
||||||
// TODO(bcmills): "all@none" seems like a totally reasonable way to
|
// TODO(bcmills): "all@none" seems like a totally reasonable way to
|
||||||
// request that we remove all module requirements, leaving only the main
|
// request that we remove all module requirements, leaving only the main
|
||||||
// module and standard library. Perhaps we should implement that someday.
|
// module and standard library. Perhaps we should implement that someday.
|
||||||
return &modload.QueryMatchesMainModuleError{
|
return &modload.QueryUpgradesAllError{
|
||||||
Pattern: q.pattern,
|
MainModules: modload.MainModules.Versions(),
|
||||||
Query: q.version,
|
Query: q.version,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -212,20 +212,20 @@ func addDeprecation(ctx context.Context, m *modinfo.ModulePublic) {
|
||||||
// in rs (which may be nil to indicate that m was not loaded from a requirement
|
// in rs (which may be nil to indicate that m was not loaded from a requirement
|
||||||
// graph).
|
// graph).
|
||||||
func moduleInfo(ctx context.Context, rs *Requirements, m module.Version, mode ListMode) *modinfo.ModulePublic {
|
func moduleInfo(ctx context.Context, rs *Requirements, m module.Version, mode ListMode) *modinfo.ModulePublic {
|
||||||
if m == Target {
|
if m.Version == "" && MainModules.Contains(m.Path) {
|
||||||
info := &modinfo.ModulePublic{
|
info := &modinfo.ModulePublic{
|
||||||
Path: m.Path,
|
Path: m.Path,
|
||||||
Version: m.Version,
|
Version: m.Version,
|
||||||
Main: true,
|
Main: true,
|
||||||
}
|
}
|
||||||
if v, ok := rawGoVersion.Load(Target); ok {
|
if v, ok := rawGoVersion.Load(m); ok {
|
||||||
info.GoVersion = v.(string)
|
info.GoVersion = v.(string)
|
||||||
} else {
|
} else {
|
||||||
panic("internal error: GoVersion not set for main module")
|
panic("internal error: GoVersion not set for main module")
|
||||||
}
|
}
|
||||||
if HasModRoot() {
|
if modRoot := MainModules.ModRoot(m); modRoot != "" {
|
||||||
info.Dir = ModRoot()
|
info.Dir = modRoot
|
||||||
info.GoMod = ModFilePath()
|
info.GoMod = modFilePath(modRoot)
|
||||||
}
|
}
|
||||||
return info
|
return info
|
||||||
}
|
}
|
||||||
|
|
@ -240,7 +240,7 @@ func moduleInfo(ctx context.Context, rs *Requirements, m module.Version, mode Li
|
||||||
}
|
}
|
||||||
|
|
||||||
// completeFromModCache fills in the extra fields in m using the module cache.
|
// completeFromModCache fills in the extra fields in m using the module cache.
|
||||||
completeFromModCache := func(m *modinfo.ModulePublic) {
|
completeFromModCache := func(m *modinfo.ModulePublic, replacedFrom string) {
|
||||||
checksumOk := func(suffix string) bool {
|
checksumOk := func(suffix string) bool {
|
||||||
return rs == nil || m.Version == "" || cfg.BuildMod == "mod" ||
|
return rs == nil || m.Version == "" || cfg.BuildMod == "mod" ||
|
||||||
modfetch.HaveSum(module.Version{Path: m.Path, Version: m.Version + suffix})
|
modfetch.HaveSum(module.Version{Path: m.Path, Version: m.Version + suffix})
|
||||||
|
|
@ -259,7 +259,7 @@ func moduleInfo(ctx context.Context, rs *Requirements, m module.Version, mode Li
|
||||||
if m.GoVersion == "" && checksumOk("/go.mod") {
|
if m.GoVersion == "" && checksumOk("/go.mod") {
|
||||||
// Load the go.mod file to determine the Go version, since it hasn't
|
// Load the go.mod file to determine the Go version, since it hasn't
|
||||||
// already been populated from rawGoVersion.
|
// already been populated from rawGoVersion.
|
||||||
if summary, err := rawGoModSummary(mod); err == nil && summary.goVersion != "" {
|
if summary, err := rawGoModSummary(mod, replacedFrom); err == nil && summary.goVersion != "" {
|
||||||
m.GoVersion = summary.goVersion
|
m.GoVersion = summary.goVersion
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -289,11 +289,11 @@ func moduleInfo(ctx context.Context, rs *Requirements, m module.Version, mode Li
|
||||||
if rs == nil {
|
if rs == nil {
|
||||||
// If this was an explicitly-versioned argument to 'go mod download' or
|
// If this was an explicitly-versioned argument to 'go mod download' or
|
||||||
// 'go list -m', report the actual requested version, not its replacement.
|
// 'go list -m', report the actual requested version, not its replacement.
|
||||||
completeFromModCache(info) // Will set m.Error in vendor mode.
|
completeFromModCache(info, "") // Will set m.Error in vendor mode.
|
||||||
return info
|
return info
|
||||||
}
|
}
|
||||||
|
|
||||||
r := Replacement(m)
|
r, replacedFrom := Replacement(m)
|
||||||
if r.Path == "" {
|
if r.Path == "" {
|
||||||
if cfg.BuildMod == "vendor" {
|
if cfg.BuildMod == "vendor" {
|
||||||
// It's tempting to fill in the "Dir" field to point within the vendor
|
// It's tempting to fill in the "Dir" field to point within the vendor
|
||||||
|
|
@ -302,7 +302,7 @@ func moduleInfo(ctx context.Context, rs *Requirements, m module.Version, mode Li
|
||||||
// interleave packages from different modules if one module path is a
|
// interleave packages from different modules if one module path is a
|
||||||
// prefix of the other.
|
// prefix of the other.
|
||||||
} else {
|
} else {
|
||||||
completeFromModCache(info)
|
completeFromModCache(info, "")
|
||||||
}
|
}
|
||||||
return info
|
return info
|
||||||
}
|
}
|
||||||
|
|
@ -322,12 +322,12 @@ func moduleInfo(ctx context.Context, rs *Requirements, m module.Version, mode Li
|
||||||
if filepath.IsAbs(r.Path) {
|
if filepath.IsAbs(r.Path) {
|
||||||
info.Replace.Dir = r.Path
|
info.Replace.Dir = r.Path
|
||||||
} else {
|
} else {
|
||||||
info.Replace.Dir = filepath.Join(ModRoot(), r.Path)
|
info.Replace.Dir = filepath.Join(replacedFrom, r.Path)
|
||||||
}
|
}
|
||||||
info.Replace.GoMod = filepath.Join(info.Replace.Dir, "go.mod")
|
info.Replace.GoMod = filepath.Join(info.Replace.Dir, "go.mod")
|
||||||
}
|
}
|
||||||
if cfg.BuildMod != "vendor" {
|
if cfg.BuildMod != "vendor" {
|
||||||
completeFromModCache(info.Replace)
|
completeFromModCache(info.Replace, replacedFrom)
|
||||||
info.Dir = info.Replace.Dir
|
info.Dir = info.Replace.Dir
|
||||||
info.GoMod = info.Replace.GoMod
|
info.GoMod = info.Replace.GoMod
|
||||||
info.Retracted = info.Replace.Retracted
|
info.Retracted = info.Replace.Retracted
|
||||||
|
|
@ -340,15 +340,14 @@ func moduleInfo(ctx context.Context, rs *Requirements, m module.Version, mode Li
|
||||||
// for modules providing packages named by path and deps. path and deps must
|
// for modules providing packages named by path and deps. path and deps must
|
||||||
// name packages that were resolved successfully with LoadPackages.
|
// name packages that were resolved successfully with LoadPackages.
|
||||||
func PackageBuildInfo(path string, deps []string) string {
|
func PackageBuildInfo(path string, deps []string) string {
|
||||||
if isStandardImportPath(path) || !Enabled() {
|
if !Enabled() {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
target, _ := findModule(loaded, path)
|
||||||
target := mustFindModule(loaded, path, path)
|
|
||||||
mdeps := make(map[module.Version]bool)
|
mdeps := make(map[module.Version]bool)
|
||||||
for _, dep := range deps {
|
for _, dep := range deps {
|
||||||
if !isStandardImportPath(dep) {
|
if m, ok := findModule(loaded, dep); ok {
|
||||||
mdeps[mustFindModule(loaded, path, dep)] = true
|
mdeps[m] = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var mods []module.Version
|
var mods []module.Version
|
||||||
|
|
@ -367,14 +366,16 @@ func PackageBuildInfo(path string, deps []string) string {
|
||||||
mv = "(devel)"
|
mv = "(devel)"
|
||||||
}
|
}
|
||||||
fmt.Fprintf(&buf, "%s\t%s\t%s", token, m.Path, mv)
|
fmt.Fprintf(&buf, "%s\t%s\t%s", token, m.Path, mv)
|
||||||
if r := Replacement(m); r.Path == "" {
|
if r, _ := Replacement(m); r.Path == "" {
|
||||||
fmt.Fprintf(&buf, "\t%s\n", modfetch.Sum(m))
|
fmt.Fprintf(&buf, "\t%s\n", modfetch.Sum(m))
|
||||||
} else {
|
} else {
|
||||||
fmt.Fprintf(&buf, "\n=>\t%s\t%s\t%s\n", r.Path, r.Version, modfetch.Sum(r))
|
fmt.Fprintf(&buf, "\n=>\t%s\t%s\t%s\n", r.Path, r.Version, modfetch.Sum(r))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
writeEntry("mod", target)
|
if target.Path != "" {
|
||||||
|
writeEntry("mod", target)
|
||||||
|
}
|
||||||
for _, mod := range mods {
|
for _, mod := range mods {
|
||||||
writeEntry("dep", mod)
|
writeEntry("dep", mod)
|
||||||
}
|
}
|
||||||
|
|
@ -382,38 +383,13 @@ func PackageBuildInfo(path string, deps []string) string {
|
||||||
return buf.String()
|
return buf.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
// mustFindModule is like findModule, but it calls base.Fatalf if the
|
|
||||||
// module can't be found.
|
|
||||||
//
|
|
||||||
// TODO(jayconrod): remove this. Callers should use findModule and return
|
|
||||||
// errors instead of relying on base.Fatalf.
|
|
||||||
func mustFindModule(ld *loader, target, path string) module.Version {
|
|
||||||
pkg, ok := ld.pkgCache.Get(path).(*loadPkg)
|
|
||||||
if ok {
|
|
||||||
if pkg.err != nil {
|
|
||||||
base.Fatalf("build %v: cannot load %v: %v", target, path, pkg.err)
|
|
||||||
}
|
|
||||||
return pkg.mod
|
|
||||||
}
|
|
||||||
|
|
||||||
if path == "command-line-arguments" {
|
|
||||||
return Target
|
|
||||||
}
|
|
||||||
|
|
||||||
base.Fatalf("build %v: cannot find module for path %v", target, path)
|
|
||||||
panic("unreachable")
|
|
||||||
}
|
|
||||||
|
|
||||||
// findModule searches for the module that contains the package at path.
|
// findModule searches for the module that contains the package at path.
|
||||||
// If the package was loaded, its containing module and true are returned.
|
// If the package was loaded, its containing module and true are returned.
|
||||||
// Otherwise, module.Version{} and false are returend.
|
// Otherwise, module.Version{} and false are returned.
|
||||||
func findModule(ld *loader, path string) (module.Version, bool) {
|
func findModule(ld *loader, path string) (module.Version, bool) {
|
||||||
if pkg, ok := ld.pkgCache.Get(path).(*loadPkg); ok {
|
if pkg, ok := ld.pkgCache.Get(path).(*loadPkg); ok {
|
||||||
return pkg.mod, pkg.mod != module.Version{}
|
return pkg.mod, pkg.mod != module.Version{}
|
||||||
}
|
}
|
||||||
if path == "command-line-arguments" {
|
|
||||||
return Target, true
|
|
||||||
}
|
|
||||||
return module.Version{}, false
|
return module.Version{}, false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -40,7 +40,7 @@ type Requirements struct {
|
||||||
depth modDepth
|
depth modDepth
|
||||||
|
|
||||||
// rootModules is the set of module versions explicitly required by the main
|
// rootModules is the set of module versions explicitly required by the main
|
||||||
// module, sorted and capped to length. It may contain duplicates, and may
|
// modules, sorted and capped to length. It may contain duplicates, and may
|
||||||
// contain multiple versions for a given module path.
|
// contain multiple versions for a given module path.
|
||||||
rootModules []module.Version
|
rootModules []module.Version
|
||||||
maxRootVersion map[string]string
|
maxRootVersion map[string]string
|
||||||
|
|
@ -99,8 +99,8 @@ var requirements *Requirements
|
||||||
// *Requirements before any other method.
|
// *Requirements before any other method.
|
||||||
func newRequirements(depth modDepth, rootModules []module.Version, direct map[string]bool) *Requirements {
|
func newRequirements(depth modDepth, rootModules []module.Version, direct map[string]bool) *Requirements {
|
||||||
for i, m := range rootModules {
|
for i, m := range rootModules {
|
||||||
if m == Target {
|
if m.Version == "" && MainModules.Contains(m.Path) {
|
||||||
panic(fmt.Sprintf("newRequirements called with untrimmed build list: rootModules[%v] is Target", i))
|
panic(fmt.Sprintf("newRequirements called with untrimmed build list: rootModules[%v] is a main module", i))
|
||||||
}
|
}
|
||||||
if m.Path == "" || m.Version == "" {
|
if m.Path == "" || m.Version == "" {
|
||||||
panic(fmt.Sprintf("bad requirement: rootModules[%v] = %v", i, m))
|
panic(fmt.Sprintf("bad requirement: rootModules[%v] = %v", i, m))
|
||||||
|
|
@ -135,9 +135,14 @@ func newRequirements(depth modDepth, rootModules []module.Version, direct map[st
|
||||||
func (rs *Requirements) initVendor(vendorList []module.Version) {
|
func (rs *Requirements) initVendor(vendorList []module.Version) {
|
||||||
rs.graphOnce.Do(func() {
|
rs.graphOnce.Do(func() {
|
||||||
mg := &ModuleGraph{
|
mg := &ModuleGraph{
|
||||||
g: mvs.NewGraph(cmpVersion, []module.Version{Target}),
|
g: mvs.NewGraph(cmpVersion, MainModules.Versions()),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if MainModules.Len() != 1 {
|
||||||
|
panic("There should be exactly one main module in Vendor mode.")
|
||||||
|
}
|
||||||
|
mainModule := MainModules.Versions()[0]
|
||||||
|
|
||||||
if rs.depth == lazy {
|
if rs.depth == lazy {
|
||||||
// The roots of a lazy module should already include every module in the
|
// The roots of a lazy module should already include every module in the
|
||||||
// vendor list, because the vendored modules are the same as those
|
// vendor list, because the vendored modules are the same as those
|
||||||
|
|
@ -158,7 +163,7 @@ func (rs *Requirements) initVendor(vendorList []module.Version) {
|
||||||
// Now we can treat the rest of the module graph as effectively “pruned
|
// Now we can treat the rest of the module graph as effectively “pruned
|
||||||
// out”, like a more aggressive version of lazy loading: in vendor mode,
|
// out”, like a more aggressive version of lazy loading: in vendor mode,
|
||||||
// the root requirements *are* the complete module graph.
|
// the root requirements *are* the complete module graph.
|
||||||
mg.g.Require(Target, rs.rootModules)
|
mg.g.Require(mainModule, rs.rootModules)
|
||||||
} else {
|
} else {
|
||||||
// The transitive requirements of the main module are not in general available
|
// The transitive requirements of the main module are not in general available
|
||||||
// from the vendor directory, and we don't actually know how we got from
|
// from the vendor directory, and we don't actually know how we got from
|
||||||
|
|
@ -170,7 +175,7 @@ func (rs *Requirements) initVendor(vendorList []module.Version) {
|
||||||
// graph, but still distinguishes between direct and indirect
|
// graph, but still distinguishes between direct and indirect
|
||||||
// dependencies.
|
// dependencies.
|
||||||
vendorMod := module.Version{Path: "vendor/modules.txt", Version: ""}
|
vendorMod := module.Version{Path: "vendor/modules.txt", Version: ""}
|
||||||
mg.g.Require(Target, append(rs.rootModules, vendorMod))
|
mg.g.Require(mainModule, append(rs.rootModules, vendorMod))
|
||||||
mg.g.Require(vendorMod, vendorList)
|
mg.g.Require(vendorMod, vendorList)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -182,8 +187,8 @@ func (rs *Requirements) initVendor(vendorList []module.Version) {
|
||||||
// path, or the zero module.Version and ok=false if the module is not a root
|
// path, or the zero module.Version and ok=false if the module is not a root
|
||||||
// dependency.
|
// dependency.
|
||||||
func (rs *Requirements) rootSelected(path string) (version string, ok bool) {
|
func (rs *Requirements) rootSelected(path string) (version string, ok bool) {
|
||||||
if path == Target.Path {
|
if MainModules.Contains(path) {
|
||||||
return Target.Version, true
|
return "", true
|
||||||
}
|
}
|
||||||
if v, ok := rs.maxRootVersion[path]; ok {
|
if v, ok := rs.maxRootVersion[path]; ok {
|
||||||
return v, true
|
return v, true
|
||||||
|
|
@ -197,7 +202,7 @@ func (rs *Requirements) rootSelected(path string) (version string, ok bool) {
|
||||||
// selection.
|
// selection.
|
||||||
func (rs *Requirements) hasRedundantRoot() bool {
|
func (rs *Requirements) hasRedundantRoot() bool {
|
||||||
for i, m := range rs.rootModules {
|
for i, m := range rs.rootModules {
|
||||||
if m.Path == Target.Path || (i > 0 && m.Path == rs.rootModules[i-1].Path) {
|
if MainModules.Contains(m.Path) || (i > 0 && m.Path == rs.rootModules[i-1].Path) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -274,10 +279,17 @@ func readModGraph(ctx context.Context, depth modDepth, roots []module.Version) (
|
||||||
mu sync.Mutex // guards mg.g and hasError during loading
|
mu sync.Mutex // guards mg.g and hasError during loading
|
||||||
hasError bool
|
hasError bool
|
||||||
mg = &ModuleGraph{
|
mg = &ModuleGraph{
|
||||||
g: mvs.NewGraph(cmpVersion, []module.Version{Target}),
|
g: mvs.NewGraph(cmpVersion, MainModules.Versions()),
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
mg.g.Require(Target, roots)
|
for _, m := range MainModules.Versions() {
|
||||||
|
// Require all roots from all main modules.
|
||||||
|
_ = TODOWorkspaces("This flattens a level of the module graph, adding the dependencies " +
|
||||||
|
"of all main modules to a single requirements struct, and losing the information of which " +
|
||||||
|
"main module required which requirement. Rework the requirements struct and change this" +
|
||||||
|
"to reflect the structure of the main modules.")
|
||||||
|
mg.g.Require(m, roots)
|
||||||
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
loadQueue = par.NewQueue(runtime.GOMAXPROCS(0))
|
loadQueue = par.NewQueue(runtime.GOMAXPROCS(0))
|
||||||
|
|
@ -404,10 +416,12 @@ func (mg *ModuleGraph) findError() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (mg *ModuleGraph) allRootsSelected() bool {
|
func (mg *ModuleGraph) allRootsSelected() bool {
|
||||||
roots, _ := mg.g.RequiredBy(Target)
|
for _, mm := range MainModules.Versions() {
|
||||||
for _, m := range roots {
|
roots, _ := mg.g.RequiredBy(mm)
|
||||||
if mg.Selected(m.Path) != m.Version {
|
for _, m := range roots {
|
||||||
return false
|
if mg.Selected(m.Path) != m.Version {
|
||||||
|
return false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
|
|
@ -447,7 +461,7 @@ func LoadModGraph(ctx context.Context, goVersion string) *ModuleGraph {
|
||||||
base.Fatalf("go: %v", err)
|
base.Fatalf("go: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
commitRequirements(ctx, modFileGoVersion(), rs)
|
commitRequirements(ctx, rs)
|
||||||
return mg
|
return mg
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -513,7 +527,7 @@ func EditBuildList(ctx context.Context, add, mustSelect []module.Version) (chang
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
commitRequirements(ctx, modFileGoVersion(), rs)
|
commitRequirements(ctx, rs)
|
||||||
return changed, err
|
return changed, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -546,10 +560,11 @@ type Conflict struct {
|
||||||
// both retain the same versions of all packages in pkgs and satisfy the
|
// both retain the same versions of all packages in pkgs and satisfy the
|
||||||
// lazy loading invariants (if applicable).
|
// lazy loading invariants (if applicable).
|
||||||
func tidyRoots(ctx context.Context, rs *Requirements, pkgs []*loadPkg) (*Requirements, error) {
|
func tidyRoots(ctx context.Context, rs *Requirements, pkgs []*loadPkg) (*Requirements, error) {
|
||||||
|
mainModule := MainModules.mustGetSingleMainModule()
|
||||||
if rs.depth == eager {
|
if rs.depth == eager {
|
||||||
return tidyEagerRoots(ctx, rs.direct, pkgs)
|
return tidyEagerRoots(ctx, mainModule, rs.direct, pkgs)
|
||||||
}
|
}
|
||||||
return tidyLazyRoots(ctx, rs.direct, pkgs)
|
return tidyLazyRoots(ctx, mainModule, rs.direct, pkgs)
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateRoots(ctx context.Context, direct map[string]bool, rs *Requirements, pkgs []*loadPkg, add []module.Version, rootsImported bool) (*Requirements, error) {
|
func updateRoots(ctx context.Context, direct map[string]bool, rs *Requirements, pkgs []*loadPkg, add []module.Version, rootsImported bool) (*Requirements, error) {
|
||||||
|
|
@ -574,10 +589,10 @@ func updateRoots(ctx context.Context, direct map[string]bool, rs *Requirements,
|
||||||
// To ensure that the loading process eventually converges, the caller should
|
// To ensure that the loading process eventually converges, the caller should
|
||||||
// add any needed roots from the tidy root set (without removing existing untidy
|
// add any needed roots from the tidy root set (without removing existing untidy
|
||||||
// roots) until the set of roots has converged.
|
// roots) until the set of roots has converged.
|
||||||
func tidyLazyRoots(ctx context.Context, direct map[string]bool, pkgs []*loadPkg) (*Requirements, error) {
|
func tidyLazyRoots(ctx context.Context, mainModule module.Version, direct map[string]bool, pkgs []*loadPkg) (*Requirements, error) {
|
||||||
var (
|
var (
|
||||||
roots []module.Version
|
roots []module.Version
|
||||||
pathIncluded = map[string]bool{Target.Path: true}
|
pathIncluded = map[string]bool{mainModule.Path: true}
|
||||||
)
|
)
|
||||||
// We start by adding roots for every package in "all".
|
// We start by adding roots for every package in "all".
|
||||||
//
|
//
|
||||||
|
|
@ -807,7 +822,7 @@ func updateLazyRoots(ctx context.Context, direct map[string]bool, rs *Requiremen
|
||||||
// We've added or upgraded one or more roots, so load the full module
|
// We've added or upgraded one or more roots, so load the full module
|
||||||
// graph so that we can update those roots to be consistent with other
|
// graph so that we can update those roots to be consistent with other
|
||||||
// requirements.
|
// requirements.
|
||||||
if cfg.BuildMod != "mod" {
|
if mustHaveCompleteRequirements() {
|
||||||
// Our changes to the roots may have moved dependencies into or out of
|
// Our changes to the roots may have moved dependencies into or out of
|
||||||
// the lazy-loading horizon, which could in turn change the selected
|
// the lazy-loading horizon, which could in turn change the selected
|
||||||
// versions of other modules. (Unlike for eager modules, for lazy
|
// versions of other modules. (Unlike for eager modules, for lazy
|
||||||
|
|
@ -855,7 +870,9 @@ func updateLazyRoots(ctx context.Context, direct map[string]bool, rs *Requiremen
|
||||||
roots = make([]module.Version, 0, len(rs.rootModules))
|
roots = make([]module.Version, 0, len(rs.rootModules))
|
||||||
rootsUpgraded = false
|
rootsUpgraded = false
|
||||||
inRootPaths := make(map[string]bool, len(rs.rootModules)+1)
|
inRootPaths := make(map[string]bool, len(rs.rootModules)+1)
|
||||||
inRootPaths[Target.Path] = true
|
for _, mm := range MainModules.Versions() {
|
||||||
|
inRootPaths[mm.Path] = true
|
||||||
|
}
|
||||||
for _, m := range rs.rootModules {
|
for _, m := range rs.rootModules {
|
||||||
if inRootPaths[m.Path] {
|
if inRootPaths[m.Path] {
|
||||||
// This root specifies a redundant path. We already retained the
|
// This root specifies a redundant path. We already retained the
|
||||||
|
|
@ -958,7 +975,7 @@ func spotCheckRoots(ctx context.Context, rs *Requirements, mods map[module.Versi
|
||||||
// tidyEagerRoots returns a minimal set of root requirements that maintains the
|
// tidyEagerRoots returns a minimal set of root requirements that maintains the
|
||||||
// selected version of every module that provided a package in pkgs, and
|
// selected version of every module that provided a package in pkgs, and
|
||||||
// includes the selected version of every such module in direct as a root.
|
// includes the selected version of every such module in direct as a root.
|
||||||
func tidyEagerRoots(ctx context.Context, direct map[string]bool, pkgs []*loadPkg) (*Requirements, error) {
|
func tidyEagerRoots(ctx context.Context, mainModule module.Version, direct map[string]bool, pkgs []*loadPkg) (*Requirements, error) {
|
||||||
var (
|
var (
|
||||||
keep []module.Version
|
keep []module.Version
|
||||||
keptPath = map[string]bool{}
|
keptPath = map[string]bool{}
|
||||||
|
|
@ -981,7 +998,7 @@ func tidyEagerRoots(ctx context.Context, direct map[string]bool, pkgs []*loadPkg
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
min, err := mvs.Req(Target, rootPaths, &mvsReqs{roots: keep})
|
min, err := mvs.Req(mainModule, rootPaths, &mvsReqs{roots: keep})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -1011,7 +1028,7 @@ func updateEagerRoots(ctx context.Context, direct map[string]bool, rs *Requireme
|
||||||
return rs, err
|
return rs, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if cfg.BuildMod != "mod" {
|
if mustHaveCompleteRequirements() {
|
||||||
// Instead of actually updating the requirements, just check that no updates
|
// Instead of actually updating the requirements, just check that no updates
|
||||||
// are needed.
|
// are needed.
|
||||||
if rs == nil {
|
if rs == nil {
|
||||||
|
|
@ -1070,7 +1087,7 @@ func updateEagerRoots(ctx context.Context, direct map[string]bool, rs *Requireme
|
||||||
// This is only for convenience and clarity for end users: in an eager module,
|
// This is only for convenience and clarity for end users: in an eager module,
|
||||||
// the choice of explicit vs. implicit dependency has no impact on MVS
|
// the choice of explicit vs. implicit dependency has no impact on MVS
|
||||||
// selection (for itself or any other module).
|
// selection (for itself or any other module).
|
||||||
keep := append(mg.BuildList()[1:], add...)
|
keep := append(mg.BuildList()[MainModules.Len():], add...)
|
||||||
for _, m := range keep {
|
for _, m := range keep {
|
||||||
if direct[m.Path] && !inRootPaths[m.Path] {
|
if direct[m.Path] && !inRootPaths[m.Path] {
|
||||||
rootPaths = append(rootPaths, m.Path)
|
rootPaths = append(rootPaths, m.Path)
|
||||||
|
|
@ -1078,16 +1095,25 @@ func updateEagerRoots(ctx context.Context, direct map[string]bool, rs *Requireme
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
min, err := mvs.Req(Target, rootPaths, &mvsReqs{roots: keep})
|
// TODO(matloob): Make roots into a map.
|
||||||
if err != nil {
|
var roots []module.Version
|
||||||
return rs, err
|
for _, mainModule := range MainModules.Versions() {
|
||||||
|
min, err := mvs.Req(mainModule, rootPaths, &mvsReqs{roots: keep})
|
||||||
|
if err != nil {
|
||||||
|
return rs, err
|
||||||
|
}
|
||||||
|
roots = append(roots, min...)
|
||||||
}
|
}
|
||||||
if rs.depth == eager && reflect.DeepEqual(min, rs.rootModules) && reflect.DeepEqual(direct, rs.direct) {
|
if MainModules.Len() > 1 {
|
||||||
|
module.Sort(roots)
|
||||||
|
}
|
||||||
|
if rs.depth == eager && reflect.DeepEqual(roots, rs.rootModules) && reflect.DeepEqual(direct, rs.direct) {
|
||||||
// The root set is unchanged and rs was already eager, so keep rs to
|
// The root set is unchanged and rs was already eager, so keep rs to
|
||||||
// preserve its cached ModuleGraph (if any).
|
// preserve its cached ModuleGraph (if any).
|
||||||
return rs, nil
|
return rs, nil
|
||||||
}
|
}
|
||||||
return newRequirements(eager, min, direct), nil
|
|
||||||
|
return newRequirements(eager, roots, direct), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// convertDepth returns a version of rs with the given depth.
|
// convertDepth returns a version of rs with the given depth.
|
||||||
|
|
@ -1117,5 +1143,5 @@ func convertDepth(ctx context.Context, rs *Requirements, depth modDepth) (*Requi
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return rs, err
|
return rs, err
|
||||||
}
|
}
|
||||||
return newRequirements(lazy, mg.BuildList()[1:], rs.direct), nil
|
return newRequirements(lazy, mg.BuildList()[MainModules.Len():], rs.direct), nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -75,7 +75,7 @@ func editRequirements(ctx context.Context, rs *Requirements, tryUpgrade, mustSel
|
||||||
// We promote the modules in mustSelect to be explicit requirements.
|
// We promote the modules in mustSelect to be explicit requirements.
|
||||||
var rootPaths []string
|
var rootPaths []string
|
||||||
for _, m := range mustSelect {
|
for _, m := range mustSelect {
|
||||||
if m.Version != "none" && m.Path != Target.Path {
|
if !MainModules.Contains(m.Path) && m.Version != "none" {
|
||||||
rootPaths = append(rootPaths, m.Path)
|
rootPaths = append(rootPaths, m.Path)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -97,7 +97,7 @@ func editRequirements(ctx context.Context, rs *Requirements, tryUpgrade, mustSel
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
roots, err = mvs.Req(Target, rootPaths, &mvsReqs{roots: mods})
|
roots, err = mvs.Req(MainModules.mustGetSingleMainModule(), rootPaths, &mvsReqs{roots: mods})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, false, err
|
return nil, false, err
|
||||||
}
|
}
|
||||||
|
|
@ -218,8 +218,8 @@ func raiseLimitsForUpgrades(ctx context.Context, maxVersion map[string]string, d
|
||||||
eagerUpgrades = tryUpgrade
|
eagerUpgrades = tryUpgrade
|
||||||
} else {
|
} else {
|
||||||
for _, m := range tryUpgrade {
|
for _, m := range tryUpgrade {
|
||||||
if m.Path == Target.Path {
|
if MainModules.Contains(m.Path) {
|
||||||
// Target is already considered to be higher than any possible m, so we
|
// The main module versions are already considered to be higher than any possible m, so we
|
||||||
// won't be upgrading to it anyway and there is no point scanning its
|
// won't be upgrading to it anyway and there is no point scanning its
|
||||||
// dependencies.
|
// dependencies.
|
||||||
continue
|
continue
|
||||||
|
|
@ -318,7 +318,7 @@ func selectPotentiallyImportedModules(ctx context.Context, limiter *versionLimit
|
||||||
|
|
||||||
mods = make([]module.Version, 0, len(limiter.selected))
|
mods = make([]module.Version, 0, len(limiter.selected))
|
||||||
for path, v := range limiter.selected {
|
for path, v := range limiter.selected {
|
||||||
if v != "none" && path != Target.Path {
|
if v != "none" && !MainModules.Contains(path) {
|
||||||
mods = append(mods, module.Version{Path: path, Version: v})
|
mods = append(mods, module.Version{Path: path, Version: v})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -334,7 +334,7 @@ func selectPotentiallyImportedModules(ctx context.Context, limiter *versionLimit
|
||||||
}
|
}
|
||||||
mods = make([]module.Version, 0, len(limiter.selected))
|
mods = make([]module.Version, 0, len(limiter.selected))
|
||||||
for path, _ := range limiter.selected {
|
for path, _ := range limiter.selected {
|
||||||
if path != Target.Path {
|
if !MainModules.Contains(path) {
|
||||||
if v := mg.Selected(path); v != "none" {
|
if v := mg.Selected(path); v != "none" {
|
||||||
mods = append(mods, module.Version{Path: path, Version: v})
|
mods = append(mods, module.Version{Path: path, Version: v})
|
||||||
}
|
}
|
||||||
|
|
@ -415,10 +415,14 @@ func (dq dqState) isDisqualified() bool {
|
||||||
// itself lazy, its unrestricted dependencies are skipped when scanning
|
// itself lazy, its unrestricted dependencies are skipped when scanning
|
||||||
// requirements.
|
// requirements.
|
||||||
func newVersionLimiter(depth modDepth, max map[string]string) *versionLimiter {
|
func newVersionLimiter(depth modDepth, max map[string]string) *versionLimiter {
|
||||||
|
selected := make(map[string]string)
|
||||||
|
for _, m := range MainModules.Versions() {
|
||||||
|
selected[m.Path] = m.Version
|
||||||
|
}
|
||||||
return &versionLimiter{
|
return &versionLimiter{
|
||||||
depth: depth,
|
depth: depth,
|
||||||
max: max,
|
max: max,
|
||||||
selected: map[string]string{Target.Path: Target.Version},
|
selected: selected,
|
||||||
dqReason: map[module.Version]dqState{},
|
dqReason: map[module.Version]dqState{},
|
||||||
requiring: map[module.Version][]module.Version{},
|
requiring: map[module.Version][]module.Version{},
|
||||||
}
|
}
|
||||||
|
|
@ -492,7 +496,7 @@ func (l *versionLimiter) Select(m module.Version) (conflict module.Version, err
|
||||||
// as is feasible, we don't want to retain test dependencies that are only
|
// as is feasible, we don't want to retain test dependencies that are only
|
||||||
// marginally relevant at best.
|
// marginally relevant at best.
|
||||||
func (l *versionLimiter) check(m module.Version, depth modDepth) dqState {
|
func (l *versionLimiter) check(m module.Version, depth modDepth) dqState {
|
||||||
if m.Version == "none" || m == Target {
|
if m.Version == "none" || m == MainModules.mustGetSingleMainModule() {
|
||||||
// version "none" has no requirements, and the dependencies of Target are
|
// version "none" has no requirements, and the dependencies of Target are
|
||||||
// tautological.
|
// tautological.
|
||||||
return dqState{}
|
return dqState{}
|
||||||
|
|
|
||||||
|
|
@ -32,6 +32,8 @@ type ImportMissingError struct {
|
||||||
Module module.Version
|
Module module.Version
|
||||||
QueryErr error
|
QueryErr error
|
||||||
|
|
||||||
|
ImportingMainModule module.Version
|
||||||
|
|
||||||
// isStd indicates whether we would expect to find the package in the standard
|
// isStd indicates whether we would expect to find the package in the standard
|
||||||
// library. This is normally true for all dotless import paths, but replace
|
// library. This is normally true for all dotless import paths, but replace
|
||||||
// directives can cause us to treat the replaced paths as also being in
|
// directives can cause us to treat the replaced paths as also being in
|
||||||
|
|
@ -71,6 +73,9 @@ func (e *ImportMissingError) Error() string {
|
||||||
if e.QueryErr != nil {
|
if e.QueryErr != nil {
|
||||||
return fmt.Sprintf("%s: %v", message, e.QueryErr)
|
return fmt.Sprintf("%s: %v", message, e.QueryErr)
|
||||||
}
|
}
|
||||||
|
if e.ImportingMainModule.Path != "" && e.ImportingMainModule != MainModules.ModContainingCWD() {
|
||||||
|
return fmt.Sprintf("%s; to add it:\n\tcd %s\n\tgo get %s", message, MainModules.ModRoot(e.ImportingMainModule), e.Path)
|
||||||
|
}
|
||||||
return fmt.Sprintf("%s; to add it:\n\tgo get %s", message, e.Path)
|
return fmt.Sprintf("%s; to add it:\n\tgo get %s", message, e.Path)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -257,11 +262,13 @@ func importFromModules(ctx context.Context, path string, rs *Requirements, mg *M
|
||||||
// Is the package in the standard library?
|
// Is the package in the standard library?
|
||||||
pathIsStd := search.IsStandardImportPath(path)
|
pathIsStd := search.IsStandardImportPath(path)
|
||||||
if pathIsStd && goroot.IsStandardPackage(cfg.GOROOT, cfg.BuildContext.Compiler, path) {
|
if pathIsStd && goroot.IsStandardPackage(cfg.GOROOT, cfg.BuildContext.Compiler, path) {
|
||||||
if targetInGorootSrc {
|
for _, mainModule := range MainModules.Versions() {
|
||||||
if dir, ok, err := dirInModule(path, targetPrefix, ModRoot(), true); err != nil {
|
if MainModules.InGorootSrc(mainModule) {
|
||||||
return module.Version{}, dir, err
|
if dir, ok, err := dirInModule(path, MainModules.PathPrefix(mainModule), MainModules.ModRoot(mainModule), true); err != nil {
|
||||||
} else if ok {
|
return module.Version{}, dir, err
|
||||||
return Target, dir, nil
|
} else if ok {
|
||||||
|
return mainModule, dir, nil
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
dir := filepath.Join(cfg.GOROOT, "src", path)
|
dir := filepath.Join(cfg.GOROOT, "src", path)
|
||||||
|
|
@ -271,8 +278,10 @@ func importFromModules(ctx context.Context, path string, rs *Requirements, mg *M
|
||||||
// -mod=vendor is special.
|
// -mod=vendor is special.
|
||||||
// Everything must be in the main module or the main module's vendor directory.
|
// Everything must be in the main module or the main module's vendor directory.
|
||||||
if cfg.BuildMod == "vendor" {
|
if cfg.BuildMod == "vendor" {
|
||||||
mainDir, mainOK, mainErr := dirInModule(path, targetPrefix, ModRoot(), true)
|
mainModule := MainModules.mustGetSingleMainModule()
|
||||||
vendorDir, vendorOK, _ := dirInModule(path, "", filepath.Join(ModRoot(), "vendor"), false)
|
modRoot := MainModules.ModRoot(mainModule)
|
||||||
|
mainDir, mainOK, mainErr := dirInModule(path, MainModules.PathPrefix(mainModule), modRoot, true)
|
||||||
|
vendorDir, vendorOK, _ := dirInModule(path, "", filepath.Join(modRoot, "vendor"), false)
|
||||||
if mainOK && vendorOK {
|
if mainOK && vendorOK {
|
||||||
return module.Version{}, "", &AmbiguousImportError{importPath: path, Dirs: []string{mainDir, vendorDir}}
|
return module.Version{}, "", &AmbiguousImportError{importPath: path, Dirs: []string{mainDir, vendorDir}}
|
||||||
}
|
}
|
||||||
|
|
@ -280,12 +289,12 @@ func importFromModules(ctx context.Context, path string, rs *Requirements, mg *M
|
||||||
// Note that we're not checking that the package exists.
|
// Note that we're not checking that the package exists.
|
||||||
// We'll leave that for load.
|
// We'll leave that for load.
|
||||||
if !vendorOK && mainDir != "" {
|
if !vendorOK && mainDir != "" {
|
||||||
return Target, mainDir, nil
|
return mainModule, mainDir, nil
|
||||||
}
|
}
|
||||||
if mainErr != nil {
|
if mainErr != nil {
|
||||||
return module.Version{}, "", mainErr
|
return module.Version{}, "", mainErr
|
||||||
}
|
}
|
||||||
readVendorList()
|
readVendorList(mainModule)
|
||||||
return vendorPkgModule[path], vendorDir, nil
|
return vendorPkgModule[path], vendorDir, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -410,69 +419,72 @@ func importFromModules(ctx context.Context, path string, rs *Requirements, mg *M
|
||||||
func queryImport(ctx context.Context, path string, rs *Requirements) (module.Version, error) {
|
func queryImport(ctx context.Context, path string, rs *Requirements) (module.Version, error) {
|
||||||
// To avoid spurious remote fetches, try the latest replacement for each
|
// To avoid spurious remote fetches, try the latest replacement for each
|
||||||
// module (golang.org/issue/26241).
|
// module (golang.org/issue/26241).
|
||||||
if index != nil {
|
var mods []module.Version
|
||||||
var mods []module.Version
|
for _, v := range MainModules.Versions() {
|
||||||
for mp, mv := range index.highestReplaced {
|
if index := MainModules.Index(v); index != nil {
|
||||||
if !maybeInModule(path, mp) {
|
for mp, mv := range index.highestReplaced {
|
||||||
continue
|
if !maybeInModule(path, mp) {
|
||||||
}
|
continue
|
||||||
if mv == "" {
|
|
||||||
// The only replacement is a wildcard that doesn't specify a version, so
|
|
||||||
// synthesize a pseudo-version with an appropriate major version and a
|
|
||||||
// timestamp below any real timestamp. That way, if the main module is
|
|
||||||
// used from within some other module, the user will be able to upgrade
|
|
||||||
// the requirement to any real version they choose.
|
|
||||||
if _, pathMajor, ok := module.SplitPathVersion(mp); ok && len(pathMajor) > 0 {
|
|
||||||
mv = module.ZeroPseudoVersion(pathMajor[1:])
|
|
||||||
} else {
|
|
||||||
mv = module.ZeroPseudoVersion("v0")
|
|
||||||
}
|
}
|
||||||
|
if mv == "" {
|
||||||
|
// The only replacement is a wildcard that doesn't specify a version, so
|
||||||
|
// synthesize a pseudo-version with an appropriate major version and a
|
||||||
|
// timestamp below any real timestamp. That way, if the main module is
|
||||||
|
// used from within some other module, the user will be able to upgrade
|
||||||
|
// the requirement to any real version they choose.
|
||||||
|
if _, pathMajor, ok := module.SplitPathVersion(mp); ok && len(pathMajor) > 0 {
|
||||||
|
mv = module.ZeroPseudoVersion(pathMajor[1:])
|
||||||
|
} else {
|
||||||
|
mv = module.ZeroPseudoVersion("v0")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mg, err := rs.Graph(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return module.Version{}, err
|
||||||
|
}
|
||||||
|
if cmpVersion(mg.Selected(mp), mv) >= 0 {
|
||||||
|
// We can't resolve the import by adding mp@mv to the module graph,
|
||||||
|
// because the selected version of mp is already at least mv.
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
mods = append(mods, module.Version{Path: mp, Version: mv})
|
||||||
}
|
}
|
||||||
mg, err := rs.Graph(ctx)
|
|
||||||
if err != nil {
|
|
||||||
return module.Version{}, err
|
|
||||||
}
|
|
||||||
if cmpVersion(mg.Selected(mp), mv) >= 0 {
|
|
||||||
// We can't resolve the import by adding mp@mv to the module graph,
|
|
||||||
// because the selected version of mp is already at least mv.
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
mods = append(mods, module.Version{Path: mp, Version: mv})
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Every module path in mods is a prefix of the import path.
|
// Every module path in mods is a prefix of the import path.
|
||||||
// As in QueryPattern, prefer the longest prefix that satisfies the import.
|
// As in QueryPattern, prefer the longest prefix that satisfies the import.
|
||||||
sort.Slice(mods, func(i, j int) bool {
|
sort.Slice(mods, func(i, j int) bool {
|
||||||
return len(mods[i].Path) > len(mods[j].Path)
|
return len(mods[i].Path) > len(mods[j].Path)
|
||||||
})
|
})
|
||||||
for _, m := range mods {
|
for _, m := range mods {
|
||||||
needSum := true
|
needSum := true
|
||||||
root, isLocal, err := fetch(ctx, m, needSum)
|
root, isLocal, err := fetch(ctx, m, needSum)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if sumErr := (*sumMissingError)(nil); errors.As(err, &sumErr) {
|
if sumErr := (*sumMissingError)(nil); errors.As(err, &sumErr) {
|
||||||
return module.Version{}, &ImportMissingSumError{importPath: path}
|
return module.Version{}, &ImportMissingSumError{importPath: path}
|
||||||
}
|
|
||||||
return module.Version{}, err
|
|
||||||
}
|
|
||||||
if _, ok, err := dirInModule(path, m.Path, root, isLocal); err != nil {
|
|
||||||
return m, err
|
|
||||||
} else if ok {
|
|
||||||
if cfg.BuildMod == "readonly" {
|
|
||||||
return module.Version{}, &ImportMissingError{Path: path, replaced: m}
|
|
||||||
}
|
|
||||||
return m, nil
|
|
||||||
}
|
}
|
||||||
|
return module.Version{}, err
|
||||||
}
|
}
|
||||||
if len(mods) > 0 && module.CheckPath(path) != nil {
|
if _, ok, err := dirInModule(path, m.Path, root, isLocal); err != nil {
|
||||||
// The package path is not valid to fetch remotely,
|
return m, err
|
||||||
// so it can only exist in a replaced module,
|
} else if ok {
|
||||||
// and we know from the above loop that it is not.
|
if cfg.BuildMod == "readonly" {
|
||||||
return module.Version{}, &PackageNotInModuleError{
|
return module.Version{}, &ImportMissingError{Path: path, replaced: m}
|
||||||
Mod: mods[0],
|
|
||||||
Query: "latest",
|
|
||||||
Pattern: path,
|
|
||||||
Replacement: Replacement(mods[0]),
|
|
||||||
}
|
}
|
||||||
|
return m, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(mods) > 0 && module.CheckPath(path) != nil {
|
||||||
|
// The package path is not valid to fetch remotely,
|
||||||
|
// so it can only exist in a replaced module,
|
||||||
|
// and we know from the above loop that it is not.
|
||||||
|
replacement, _ := Replacement(mods[0])
|
||||||
|
return module.Version{}, &PackageNotInModuleError{
|
||||||
|
Mod: mods[0],
|
||||||
|
Query: "latest",
|
||||||
|
Pattern: path,
|
||||||
|
Replacement: replacement,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -638,14 +650,14 @@ func dirInModule(path, mpath, mdir string, isLocal bool) (dir string, haveGoFile
|
||||||
// The isLocal return value reports whether the replacement,
|
// The isLocal return value reports whether the replacement,
|
||||||
// if any, is local to the filesystem.
|
// if any, is local to the filesystem.
|
||||||
func fetch(ctx context.Context, mod module.Version, needSum bool) (dir string, isLocal bool, err error) {
|
func fetch(ctx context.Context, mod module.Version, needSum bool) (dir string, isLocal bool, err error) {
|
||||||
if mod == Target {
|
if modRoot := MainModules.ModRoot(mod); modRoot != "" {
|
||||||
return ModRoot(), true, nil
|
return modRoot, true, nil
|
||||||
}
|
}
|
||||||
if r := Replacement(mod); r.Path != "" {
|
if r, replacedFrom := Replacement(mod); r.Path != "" {
|
||||||
if r.Version == "" {
|
if r.Version == "" {
|
||||||
dir = r.Path
|
dir = r.Path
|
||||||
if !filepath.IsAbs(dir) {
|
if !filepath.IsAbs(dir) {
|
||||||
dir = filepath.Join(ModRoot(), dir)
|
dir = filepath.Join(replacedFrom, dir)
|
||||||
}
|
}
|
||||||
// Ensure that the replacement directory actually exists:
|
// Ensure that the replacement directory actually exists:
|
||||||
// dirInModule does not report errors for missing modules,
|
// dirInModule does not report errors for missing modules,
|
||||||
|
|
@ -667,7 +679,7 @@ func fetch(ctx context.Context, mod module.Version, needSum bool) (dir string, i
|
||||||
mod = r
|
mod = r
|
||||||
}
|
}
|
||||||
|
|
||||||
if HasModRoot() && cfg.BuildMod == "readonly" && needSum && !modfetch.HaveSum(mod) {
|
if HasModRoot() && cfg.BuildMod == "readonly" && !inWorkspaceMode() && needSum && !modfetch.HaveSum(mod) {
|
||||||
return "", false, module.VersionError(mod, &sumMissingError{})
|
return "", false, module.VersionError(mod, &sumMissingError{})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -72,14 +72,18 @@ func ListModules(ctx context.Context, args []string, mode ListMode) ([]*modinfo.
|
||||||
}
|
}
|
||||||
|
|
||||||
if err == nil {
|
if err == nil {
|
||||||
commitRequirements(ctx, modFileGoVersion(), rs)
|
commitRequirements(ctx, rs)
|
||||||
}
|
}
|
||||||
return mods, err
|
return mods, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func listModules(ctx context.Context, rs *Requirements, args []string, mode ListMode) (_ *Requirements, mods []*modinfo.ModulePublic, mgErr error) {
|
func listModules(ctx context.Context, rs *Requirements, args []string, mode ListMode) (_ *Requirements, mods []*modinfo.ModulePublic, mgErr error) {
|
||||||
if len(args) == 0 {
|
if len(args) == 0 {
|
||||||
return rs, []*modinfo.ModulePublic{moduleInfo(ctx, rs, Target, mode)}, nil
|
var ms []*modinfo.ModulePublic
|
||||||
|
for _, m := range MainModules.Versions() {
|
||||||
|
ms = append(ms, moduleInfo(ctx, rs, m, mode))
|
||||||
|
}
|
||||||
|
return rs, ms, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
needFullGraph := false
|
needFullGraph := false
|
||||||
|
|
|
||||||
|
|
@ -274,7 +274,9 @@ func LoadPackages(ctx context.Context, opts PackageOpts, patterns ...string) (ma
|
||||||
|
|
||||||
// If we're outside of a module, ensure that the failure mode
|
// If we're outside of a module, ensure that the failure mode
|
||||||
// indicates that.
|
// indicates that.
|
||||||
ModRoot()
|
if !HasModRoot() {
|
||||||
|
die()
|
||||||
|
}
|
||||||
|
|
||||||
if ld != nil {
|
if ld != nil {
|
||||||
m.AddError(err)
|
m.AddError(err)
|
||||||
|
|
@ -306,7 +308,7 @@ func LoadPackages(ctx context.Context, opts PackageOpts, patterns ...string) (ma
|
||||||
// The initial roots are the packages in the main module.
|
// The initial roots are the packages in the main module.
|
||||||
// loadFromRoots will expand that to "all".
|
// loadFromRoots will expand that to "all".
|
||||||
m.Errs = m.Errs[:0]
|
m.Errs = m.Errs[:0]
|
||||||
matchPackages(ctx, m, opts.Tags, omitStd, []module.Version{Target})
|
matchPackages(ctx, m, opts.Tags, omitStd, MainModules.Versions())
|
||||||
} else {
|
} else {
|
||||||
// Starting with the packages in the main module,
|
// Starting with the packages in the main module,
|
||||||
// enumerate the full list of "all".
|
// enumerate the full list of "all".
|
||||||
|
|
@ -401,13 +403,21 @@ func LoadPackages(ctx context.Context, opts PackageOpts, patterns ...string) (ma
|
||||||
// loaded.requirements, but here we may have also loaded (and want to
|
// loaded.requirements, but here we may have also loaded (and want to
|
||||||
// preserve checksums for) additional entities from compatRS, which are
|
// preserve checksums for) additional entities from compatRS, which are
|
||||||
// only needed for compatibility with ld.TidyCompatibleVersion.
|
// only needed for compatibility with ld.TidyCompatibleVersion.
|
||||||
modfetch.WriteGoSum(keep)
|
if err := modfetch.WriteGoSum(keep, mustHaveCompleteRequirements()); err != nil {
|
||||||
|
base.Fatalf("go: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the go.mod file's Go version if necessary.
|
||||||
|
modFile := MainModules.ModFile(MainModules.mustGetSingleMainModule())
|
||||||
|
if ld.GoVersion != "" {
|
||||||
|
modFile.AddGoStmt(ld.GoVersion)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Success! Update go.mod and go.sum (if needed) and return the results.
|
// Success! Update go.mod and go.sum (if needed) and return the results.
|
||||||
loaded = ld
|
loaded = ld
|
||||||
commitRequirements(ctx, loaded.GoVersion, loaded.requirements)
|
commitRequirements(ctx, loaded.requirements)
|
||||||
|
|
||||||
for _, pkg := range ld.pkgs {
|
for _, pkg := range ld.pkgs {
|
||||||
if !pkg.isTest() {
|
if !pkg.isTest() {
|
||||||
|
|
@ -436,14 +446,23 @@ func matchLocalDirs(ctx context.Context, m *search.Match, rs *Requirements) {
|
||||||
if !filepath.IsAbs(dir) {
|
if !filepath.IsAbs(dir) {
|
||||||
absDir = filepath.Join(base.Cwd(), dir)
|
absDir = filepath.Join(base.Cwd(), dir)
|
||||||
}
|
}
|
||||||
if search.InDir(absDir, cfg.GOROOTsrc) == "" && search.InDir(absDir, ModRoot()) == "" && pathInModuleCache(ctx, absDir, rs) == "" {
|
|
||||||
|
modRoot := findModuleRoot(absDir)
|
||||||
|
found := false
|
||||||
|
for _, mod := range MainModules.Versions() {
|
||||||
|
if MainModules.ModRoot(mod) == modRoot {
|
||||||
|
found = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !found && search.InDir(absDir, cfg.GOROOTsrc) == "" && pathInModuleCache(ctx, absDir, rs) == "" {
|
||||||
m.Dirs = []string{}
|
m.Dirs = []string{}
|
||||||
m.AddError(fmt.Errorf("directory prefix %s outside available modules", base.ShortPath(absDir)))
|
m.AddError(fmt.Errorf("directory prefix %s outside available modules", base.ShortPath(absDir)))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
m.MatchDirs()
|
m.MatchDirs(modRoots)
|
||||||
}
|
}
|
||||||
|
|
||||||
// resolveLocalPackage resolves a filesystem path to a package path.
|
// resolveLocalPackage resolves a filesystem path to a package path.
|
||||||
|
|
@ -485,49 +504,69 @@ func resolveLocalPackage(ctx context.Context, dir string, rs *Requirements) (str
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if modRoot != "" && absDir == modRoot {
|
for _, mod := range MainModules.Versions() {
|
||||||
if absDir == cfg.GOROOTsrc {
|
modRoot := MainModules.ModRoot(mod)
|
||||||
return "", errPkgIsGorootSrc
|
if modRoot != "" && absDir == modRoot {
|
||||||
|
if absDir == cfg.GOROOTsrc {
|
||||||
|
return "", errPkgIsGorootSrc
|
||||||
|
}
|
||||||
|
return MainModules.PathPrefix(mod), nil
|
||||||
}
|
}
|
||||||
return targetPrefix, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Note: The checks for @ here are just to avoid misinterpreting
|
// Note: The checks for @ here are just to avoid misinterpreting
|
||||||
// the module cache directories (formerly GOPATH/src/mod/foo@v1.5.2/bar).
|
// the module cache directories (formerly GOPATH/src/mod/foo@v1.5.2/bar).
|
||||||
// It's not strictly necessary but helpful to keep the checks.
|
// It's not strictly necessary but helpful to keep the checks.
|
||||||
if modRoot != "" && strings.HasPrefix(absDir, modRoot+string(filepath.Separator)) && !strings.Contains(absDir[len(modRoot):], "@") {
|
var pkgNotFoundErr error
|
||||||
suffix := filepath.ToSlash(absDir[len(modRoot):])
|
pkgNotFoundLongestPrefix := ""
|
||||||
if strings.HasPrefix(suffix, "/vendor/") {
|
for _, mainModule := range MainModules.Versions() {
|
||||||
if cfg.BuildMod != "vendor" {
|
modRoot := MainModules.ModRoot(mainModule)
|
||||||
return "", fmt.Errorf("without -mod=vendor, directory %s has no package path", absDir)
|
if modRoot != "" && strings.HasPrefix(absDir, modRoot+string(filepath.Separator)) && !strings.Contains(absDir[len(modRoot):], "@") {
|
||||||
|
suffix := filepath.ToSlash(absDir[len(modRoot):])
|
||||||
|
if strings.HasPrefix(suffix, "/vendor/") {
|
||||||
|
if cfg.BuildMod != "vendor" {
|
||||||
|
return "", fmt.Errorf("without -mod=vendor, directory %s has no package path", absDir)
|
||||||
|
}
|
||||||
|
|
||||||
|
readVendorList(mainModule)
|
||||||
|
pkg := strings.TrimPrefix(suffix, "/vendor/")
|
||||||
|
if _, ok := vendorPkgModule[pkg]; !ok {
|
||||||
|
return "", fmt.Errorf("directory %s is not a package listed in vendor/modules.txt", absDir)
|
||||||
|
}
|
||||||
|
return pkg, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
readVendorList()
|
mainModulePrefix := MainModules.PathPrefix(mainModule)
|
||||||
pkg := strings.TrimPrefix(suffix, "/vendor/")
|
if mainModulePrefix == "" {
|
||||||
if _, ok := vendorPkgModule[pkg]; !ok {
|
pkg := strings.TrimPrefix(suffix, "/")
|
||||||
return "", fmt.Errorf("directory %s is not a package listed in vendor/modules.txt", absDir)
|
if pkg == "builtin" {
|
||||||
|
// "builtin" is a pseudo-package with a real source file.
|
||||||
|
// It's not included in "std", so it shouldn't resolve from "."
|
||||||
|
// within module "std" either.
|
||||||
|
return "", errPkgIsBuiltin
|
||||||
|
}
|
||||||
|
return pkg, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
pkg := mainModulePrefix + suffix
|
||||||
|
if _, ok, err := dirInModule(pkg, mainModulePrefix, modRoot, true); err != nil {
|
||||||
|
return "", err
|
||||||
|
} else if !ok {
|
||||||
|
// This main module could contain the directory but doesn't. Other main
|
||||||
|
// modules might contain the directory, so wait till we finish the loop
|
||||||
|
// to see if another main module contains directory. But if not,
|
||||||
|
// return an error.
|
||||||
|
if len(mainModulePrefix) > len(pkgNotFoundLongestPrefix) {
|
||||||
|
pkgNotFoundLongestPrefix = mainModulePrefix
|
||||||
|
pkgNotFoundErr = &PackageNotInModuleError{MainModules: []module.Version{mainModule}, Pattern: pkg}
|
||||||
|
}
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
return pkg, nil
|
return pkg, nil
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if targetPrefix == "" {
|
if pkgNotFoundErr != nil {
|
||||||
pkg := strings.TrimPrefix(suffix, "/")
|
return "", pkgNotFoundErr
|
||||||
if pkg == "builtin" {
|
|
||||||
// "builtin" is a pseudo-package with a real source file.
|
|
||||||
// It's not included in "std", so it shouldn't resolve from "."
|
|
||||||
// within module "std" either.
|
|
||||||
return "", errPkgIsBuiltin
|
|
||||||
}
|
|
||||||
return pkg, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
pkg := targetPrefix + suffix
|
|
||||||
if _, ok, err := dirInModule(pkg, targetPrefix, modRoot, true); err != nil {
|
|
||||||
return "", err
|
|
||||||
} else if !ok {
|
|
||||||
return "", &PackageNotInModuleError{Mod: Target, Pattern: pkg}
|
|
||||||
}
|
|
||||||
return pkg, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if sub := search.InDir(absDir, cfg.GOROOTsrc); sub != "" && sub != "." && !strings.Contains(sub, "@") {
|
if sub := search.InDir(absDir, cfg.GOROOTsrc); sub != "" && sub != "." && !strings.Contains(sub, "@") {
|
||||||
|
|
@ -557,10 +596,10 @@ func pathInModuleCache(ctx context.Context, dir string, rs *Requirements) string
|
||||||
tryMod := func(m module.Version) (string, bool) {
|
tryMod := func(m module.Version) (string, bool) {
|
||||||
var root string
|
var root string
|
||||||
var err error
|
var err error
|
||||||
if repl := Replacement(m); repl.Path != "" && repl.Version == "" {
|
if repl, replModRoot := Replacement(m); repl.Path != "" && repl.Version == "" {
|
||||||
root = repl.Path
|
root = repl.Path
|
||||||
if !filepath.IsAbs(root) {
|
if !filepath.IsAbs(root) {
|
||||||
root = filepath.Join(ModRoot(), root)
|
root = filepath.Join(replModRoot, root)
|
||||||
}
|
}
|
||||||
} else if repl.Path != "" {
|
} else if repl.Path != "" {
|
||||||
root, err = modfetch.DownloadDir(repl)
|
root, err = modfetch.DownloadDir(repl)
|
||||||
|
|
@ -645,14 +684,14 @@ func ImportFromFiles(ctx context.Context, gofiles []string) {
|
||||||
return roots
|
return roots
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
commitRequirements(ctx, loaded.GoVersion, loaded.requirements)
|
commitRequirements(ctx, loaded.requirements)
|
||||||
}
|
}
|
||||||
|
|
||||||
// DirImportPath returns the effective import path for dir,
|
// DirImportPath returns the effective import path for dir,
|
||||||
// provided it is within the main module, or else returns ".".
|
// provided it is within a main module, or else returns ".".
|
||||||
func DirImportPath(ctx context.Context, dir string) string {
|
func (mms *MainModuleSet) DirImportPath(ctx context.Context, dir string) (path string, m module.Version) {
|
||||||
if !HasModRoot() {
|
if !HasModRoot() {
|
||||||
return "."
|
return ".", module.Version{}
|
||||||
}
|
}
|
||||||
LoadModFile(ctx) // Sets targetPrefix.
|
LoadModFile(ctx) // Sets targetPrefix.
|
||||||
|
|
||||||
|
|
@ -662,17 +701,32 @@ func DirImportPath(ctx context.Context, dir string) string {
|
||||||
dir = filepath.Clean(dir)
|
dir = filepath.Clean(dir)
|
||||||
}
|
}
|
||||||
|
|
||||||
if dir == modRoot {
|
var longestPrefix string
|
||||||
return targetPrefix
|
var longestPrefixPath string
|
||||||
}
|
var longestPrefixVersion module.Version
|
||||||
if strings.HasPrefix(dir, modRoot+string(filepath.Separator)) {
|
for _, v := range mms.Versions() {
|
||||||
suffix := filepath.ToSlash(dir[len(modRoot):])
|
modRoot := mms.ModRoot(v)
|
||||||
if strings.HasPrefix(suffix, "/vendor/") {
|
if dir == modRoot {
|
||||||
return strings.TrimPrefix(suffix, "/vendor/")
|
return mms.PathPrefix(v), v
|
||||||
|
}
|
||||||
|
if strings.HasPrefix(dir, modRoot+string(filepath.Separator)) {
|
||||||
|
pathPrefix := MainModules.PathPrefix(v)
|
||||||
|
if pathPrefix > longestPrefix {
|
||||||
|
longestPrefix = pathPrefix
|
||||||
|
longestPrefixVersion = v
|
||||||
|
suffix := filepath.ToSlash(dir[len(modRoot):])
|
||||||
|
if strings.HasPrefix(suffix, "/vendor/") {
|
||||||
|
longestPrefixPath = strings.TrimPrefix(suffix, "/vendor/")
|
||||||
|
}
|
||||||
|
longestPrefixPath = mms.PathPrefix(v) + suffix
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return targetPrefix + suffix
|
|
||||||
}
|
}
|
||||||
return "."
|
if len(longestPrefix) > 0 {
|
||||||
|
return longestPrefixPath, longestPrefixVersion
|
||||||
|
}
|
||||||
|
|
||||||
|
return ".", module.Version{}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ImportMap returns the actual package import path
|
// ImportMap returns the actual package import path
|
||||||
|
|
@ -894,10 +948,7 @@ func (pkg *loadPkg) fromExternalModule() bool {
|
||||||
if pkg.mod.Path == "" {
|
if pkg.mod.Path == "" {
|
||||||
return false // loaded from the standard library, not a module
|
return false // loaded from the standard library, not a module
|
||||||
}
|
}
|
||||||
if pkg.mod.Path == Target.Path {
|
return !MainModules.Contains(pkg.mod.Path)
|
||||||
return false // loaded from the main module.
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var errMissing = errors.New("cannot find package")
|
var errMissing = errors.New("cannot find package")
|
||||||
|
|
@ -915,7 +966,7 @@ func loadFromRoots(ctx context.Context, params loaderParams) *loader {
|
||||||
}
|
}
|
||||||
|
|
||||||
if ld.GoVersion == "" {
|
if ld.GoVersion == "" {
|
||||||
ld.GoVersion = modFileGoVersion()
|
ld.GoVersion = MainModules.GoVersion()
|
||||||
|
|
||||||
if ld.Tidy && semver.Compare("v"+ld.GoVersion, "v"+LatestGoVersion()) > 0 {
|
if ld.Tidy && semver.Compare("v"+ld.GoVersion, "v"+LatestGoVersion()) > 0 {
|
||||||
ld.errorf("go mod tidy: go.mod file indicates go %s, but maximum supported version is %s\n", ld.GoVersion, LatestGoVersion())
|
ld.errorf("go mod tidy: go.mod file indicates go %s, but maximum supported version is %s\n", ld.GoVersion, LatestGoVersion())
|
||||||
|
|
@ -1168,7 +1219,7 @@ func (ld *loader) updateRequirements(ctx context.Context) (changed bool, err err
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, pkg := range ld.pkgs {
|
for _, pkg := range ld.pkgs {
|
||||||
if pkg.mod != Target {
|
if pkg.mod.Version != "" || !MainModules.Contains(pkg.mod.Path) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
for _, dep := range pkg.imports {
|
for _, dep := range pkg.imports {
|
||||||
|
|
@ -1327,6 +1378,15 @@ func (ld *loader) resolveMissingImports(ctx context.Context) (modAddedBy map[mod
|
||||||
var err error
|
var err error
|
||||||
mod, err = queryImport(ctx, pkg.path, ld.requirements)
|
mod, err = queryImport(ctx, pkg.path, ld.requirements)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
var ime *ImportMissingError
|
||||||
|
if errors.As(err, &ime) {
|
||||||
|
for curstack := pkg.stack; curstack != nil; curstack = curstack.stack {
|
||||||
|
if MainModules.Contains(curstack.mod.Path) {
|
||||||
|
ime.ImportingMainModule = curstack.mod
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
// pkg.err was already non-nil, so we can reasonably attribute the error
|
// pkg.err was already non-nil, so we can reasonably attribute the error
|
||||||
// for pkg to either the original error or the one returned by
|
// for pkg to either the original error or the one returned by
|
||||||
// queryImport. The existing error indicates only that we couldn't find
|
// queryImport. The existing error indicates only that we couldn't find
|
||||||
|
|
@ -1425,7 +1485,7 @@ func (ld *loader) applyPkgFlags(ctx context.Context, pkg *loadPkg, flags loadPkg
|
||||||
// so it's ok if we call it more than is strictly necessary.
|
// so it's ok if we call it more than is strictly necessary.
|
||||||
wantTest := false
|
wantTest := false
|
||||||
switch {
|
switch {
|
||||||
case ld.allPatternIsRoot && pkg.mod == Target:
|
case ld.allPatternIsRoot && MainModules.Contains(pkg.mod.Path):
|
||||||
// We are loading the "all" pattern, which includes packages imported by
|
// We are loading the "all" pattern, which includes packages imported by
|
||||||
// tests in the main module. This package is in the main module, so we
|
// tests in the main module. This package is in the main module, so we
|
||||||
// need to identify the imports of its test even if LoadTests is not set.
|
// need to identify the imports of its test even if LoadTests is not set.
|
||||||
|
|
@ -1446,7 +1506,7 @@ func (ld *loader) applyPkgFlags(ctx context.Context, pkg *loadPkg, flags loadPkg
|
||||||
|
|
||||||
if wantTest {
|
if wantTest {
|
||||||
var testFlags loadPkgFlags
|
var testFlags loadPkgFlags
|
||||||
if pkg.mod == Target || (ld.allClosesOverTests && new.has(pkgInAll)) {
|
if MainModules.Contains(pkg.mod.Path) || (ld.allClosesOverTests && new.has(pkgInAll)) {
|
||||||
// Tests of packages in the main module are in "all", in the sense that
|
// Tests of packages in the main module are in "all", in the sense that
|
||||||
// they cause the packages they import to also be in "all". So are tests
|
// they cause the packages they import to also be in "all". So are tests
|
||||||
// of packages in "all" if "all" closes over test dependencies.
|
// of packages in "all" if "all" closes over test dependencies.
|
||||||
|
|
@ -1593,7 +1653,7 @@ func (ld *loader) load(ctx context.Context, pkg *loadPkg) {
|
||||||
if pkg.dir == "" {
|
if pkg.dir == "" {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if pkg.mod == Target {
|
if MainModules.Contains(pkg.mod.Path) {
|
||||||
// Go ahead and mark pkg as in "all". This provides the invariant that a
|
// Go ahead and mark pkg as in "all". This provides the invariant that a
|
||||||
// package that is *only* imported by other packages in "all" is always
|
// package that is *only* imported by other packages in "all" is always
|
||||||
// marked as such before loading its imports.
|
// marked as such before loading its imports.
|
||||||
|
|
@ -1698,13 +1758,14 @@ func (ld *loader) stdVendor(parentPath, path string) string {
|
||||||
}
|
}
|
||||||
|
|
||||||
if str.HasPathPrefix(parentPath, "cmd") {
|
if str.HasPathPrefix(parentPath, "cmd") {
|
||||||
if !ld.VendorModulesInGOROOTSrc || Target.Path != "cmd" {
|
if !ld.VendorModulesInGOROOTSrc || !MainModules.Contains("cmd") {
|
||||||
vendorPath := pathpkg.Join("cmd", "vendor", path)
|
vendorPath := pathpkg.Join("cmd", "vendor", path)
|
||||||
|
|
||||||
if _, err := os.Stat(filepath.Join(cfg.GOROOTsrc, filepath.FromSlash(vendorPath))); err == nil {
|
if _, err := os.Stat(filepath.Join(cfg.GOROOTsrc, filepath.FromSlash(vendorPath))); err == nil {
|
||||||
return vendorPath
|
return vendorPath
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if !ld.VendorModulesInGOROOTSrc || Target.Path != "std" || str.HasPathPrefix(parentPath, "vendor") {
|
} else if !ld.VendorModulesInGOROOTSrc || !MainModules.Contains("std") || str.HasPathPrefix(parentPath, "vendor") {
|
||||||
// If we are outside of the 'std' module, resolve imports from within 'std'
|
// If we are outside of the 'std' module, resolve imports from within 'std'
|
||||||
// to the vendor directory.
|
// to the vendor directory.
|
||||||
//
|
//
|
||||||
|
|
@ -1753,7 +1814,7 @@ func (ld *loader) checkMultiplePaths() {
|
||||||
|
|
||||||
firstPath := map[module.Version]string{}
|
firstPath := map[module.Version]string{}
|
||||||
for _, mod := range mods {
|
for _, mod := range mods {
|
||||||
src := resolveReplacement(mod)
|
src, _ := resolveReplacement(mod)
|
||||||
if prev, ok := firstPath[src]; !ok {
|
if prev, ok := firstPath[src]; !ok {
|
||||||
firstPath[src] = mod.Path
|
firstPath[src] = mod.Path
|
||||||
} else if prev != mod.Path {
|
} else if prev != mod.Path {
|
||||||
|
|
@ -1781,7 +1842,7 @@ func (ld *loader) checkTidyCompatibility(ctx context.Context, rs *Requirements)
|
||||||
fmt.Fprintln(os.Stderr)
|
fmt.Fprintln(os.Stderr)
|
||||||
|
|
||||||
goFlag := ""
|
goFlag := ""
|
||||||
if ld.GoVersion != modFileGoVersion() {
|
if ld.GoVersion != MainModules.GoVersion() {
|
||||||
goFlag = " -go=" + ld.GoVersion
|
goFlag = " -go=" + ld.GoVersion
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -56,11 +56,9 @@ const (
|
||||||
go117LazyTODO = false
|
go117LazyTODO = false
|
||||||
)
|
)
|
||||||
|
|
||||||
var modFile *modfile.File
|
|
||||||
|
|
||||||
// modFileGoVersion returns the (non-empty) Go version at which the requirements
|
// modFileGoVersion returns the (non-empty) Go version at which the requirements
|
||||||
// in modFile are intepreted, or the latest Go version if modFile is nil.
|
// in modFile are interpreted, or the latest Go version if modFile is nil.
|
||||||
func modFileGoVersion() string {
|
func modFileGoVersion(modFile *modfile.File) string {
|
||||||
if modFile == nil {
|
if modFile == nil {
|
||||||
return LatestGoVersion()
|
return LatestGoVersion()
|
||||||
}
|
}
|
||||||
|
|
@ -92,9 +90,6 @@ type modFileIndex struct {
|
||||||
exclude map[module.Version]bool
|
exclude map[module.Version]bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// index is the index of the go.mod file as of when it was last read or written.
|
|
||||||
var index *modFileIndex
|
|
||||||
|
|
||||||
type requireMeta struct {
|
type requireMeta struct {
|
||||||
indirect bool
|
indirect bool
|
||||||
}
|
}
|
||||||
|
|
@ -137,8 +132,10 @@ var ErrDisallowed = errors.New("disallowed module version")
|
||||||
// CheckExclusions returns an error equivalent to ErrDisallowed if module m is
|
// CheckExclusions returns an error equivalent to ErrDisallowed if module m is
|
||||||
// excluded by the main module's go.mod file.
|
// excluded by the main module's go.mod file.
|
||||||
func CheckExclusions(ctx context.Context, m module.Version) error {
|
func CheckExclusions(ctx context.Context, m module.Version) error {
|
||||||
if index != nil && index.exclude[m] {
|
for _, mainModule := range MainModules.Versions() {
|
||||||
return module.VersionError(m, errExcluded)
|
if index := MainModules.Index(mainModule); index != nil && index.exclude[m] {
|
||||||
|
return module.VersionError(m, errExcluded)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
@ -170,7 +167,7 @@ func CheckRetractions(ctx context.Context, m module.Version) (err error) {
|
||||||
// Cannot be retracted.
|
// Cannot be retracted.
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
if repl := Replacement(module.Version{Path: m.Path}); repl.Path != "" {
|
if repl, _ := Replacement(module.Version{Path: m.Path}); repl.Path != "" {
|
||||||
// All versions of the module were replaced.
|
// All versions of the module were replaced.
|
||||||
// Don't load retractions, since we'd just load the replacement.
|
// Don't load retractions, since we'd just load the replacement.
|
||||||
return nil
|
return nil
|
||||||
|
|
@ -187,11 +184,11 @@ func CheckRetractions(ctx context.Context, m module.Version) (err error) {
|
||||||
// We load the raw file here: the go.mod file may have a different module
|
// We load the raw file here: the go.mod file may have a different module
|
||||||
// path that we expect if the module or its repository was renamed.
|
// path that we expect if the module or its repository was renamed.
|
||||||
// We still want to apply retractions to other aliases of the module.
|
// We still want to apply retractions to other aliases of the module.
|
||||||
rm, err := queryLatestVersionIgnoringRetractions(ctx, m.Path)
|
rm, replacedFrom, err := queryLatestVersionIgnoringRetractions(ctx, m.Path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
summary, err := rawGoModSummary(rm)
|
summary, err := rawGoModSummary(rm, replacedFrom)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
@ -289,51 +286,72 @@ func CheckDeprecation(ctx context.Context, m module.Version) (deprecation string
|
||||||
// Don't look up deprecation.
|
// Don't look up deprecation.
|
||||||
return "", nil
|
return "", nil
|
||||||
}
|
}
|
||||||
if repl := Replacement(module.Version{Path: m.Path}); repl.Path != "" {
|
if repl, _ := Replacement(module.Version{Path: m.Path}); repl.Path != "" {
|
||||||
// All versions of the module were replaced.
|
// All versions of the module were replaced.
|
||||||
// We'll look up deprecation separately for the replacement.
|
// We'll look up deprecation separately for the replacement.
|
||||||
return "", nil
|
return "", nil
|
||||||
}
|
}
|
||||||
|
|
||||||
latest, err := queryLatestVersionIgnoringRetractions(ctx, m.Path)
|
latest, replacedFrom, err := queryLatestVersionIgnoringRetractions(ctx, m.Path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
summary, err := rawGoModSummary(latest)
|
summary, err := rawGoModSummary(latest, replacedFrom)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
return summary.deprecated, nil
|
return summary.deprecated, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Replacement returns the replacement for mod, if any, from go.mod.
|
func replacement(mod module.Version, index *modFileIndex) (fromVersion string, to module.Version, ok bool) {
|
||||||
|
if r, ok := index.replace[mod]; ok {
|
||||||
|
return mod.Version, r, true
|
||||||
|
}
|
||||||
|
if r, ok := index.replace[module.Version{Path: mod.Path}]; ok {
|
||||||
|
return "", r, true
|
||||||
|
}
|
||||||
|
return "", module.Version{}, false
|
||||||
|
}
|
||||||
|
|
||||||
|
// Replacement returns the replacement for mod, if any, and and the module root
|
||||||
|
// directory of the main module containing the replace directive.
|
||||||
// If there is no replacement for mod, Replacement returns
|
// If there is no replacement for mod, Replacement returns
|
||||||
// a module.Version with Path == "".
|
// a module.Version with Path == "".
|
||||||
func Replacement(mod module.Version) module.Version {
|
func Replacement(mod module.Version) (module.Version, string) {
|
||||||
if index != nil {
|
_ = TODOWorkspaces("Support replaces in the go.work file.")
|
||||||
if r, ok := index.replace[mod]; ok {
|
foundFrom, found, foundModRoot := "", module.Version{}, ""
|
||||||
return r
|
for _, v := range MainModules.Versions() {
|
||||||
}
|
if index := MainModules.Index(v); index != nil {
|
||||||
if r, ok := index.replace[module.Version{Path: mod.Path}]; ok {
|
if from, r, ok := replacement(mod, index); ok {
|
||||||
return r
|
modRoot := MainModules.ModRoot(v)
|
||||||
|
if foundModRoot != "" && foundFrom != from && found != r {
|
||||||
|
_ = TODOWorkspaces("once the go.work file supports replaces, recommend them as a way to override conflicts")
|
||||||
|
base.Errorf("conflicting replacements found for %v in workspace modules defined by %v and %v",
|
||||||
|
mod, modFilePath(foundModRoot), modFilePath(modRoot))
|
||||||
|
return found, foundModRoot
|
||||||
|
}
|
||||||
|
found, foundModRoot = r, modRoot
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return module.Version{}
|
return found, foundModRoot
|
||||||
}
|
}
|
||||||
|
|
||||||
// resolveReplacement returns the module actually used to load the source code
|
// resolveReplacement returns the module actually used to load the source code
|
||||||
// for m: either m itself, or the replacement for m (iff m is replaced).
|
// for m: either m itself, or the replacement for m (iff m is replaced).
|
||||||
func resolveReplacement(m module.Version) module.Version {
|
// It also returns the modroot of the module providing the replacement if
|
||||||
if r := Replacement(m); r.Path != "" {
|
// one was found.
|
||||||
return r
|
func resolveReplacement(m module.Version) (module.Version, string) {
|
||||||
|
if r, replacedFrom := Replacement(m); r.Path != "" {
|
||||||
|
return r, replacedFrom
|
||||||
}
|
}
|
||||||
return m
|
return m, ""
|
||||||
}
|
}
|
||||||
|
|
||||||
// indexModFile rebuilds the index of modFile.
|
// indexModFile rebuilds the index of modFile.
|
||||||
// If modFile has been changed since it was first read,
|
// If modFile has been changed since it was first read,
|
||||||
// modFile.Cleanup must be called before indexModFile.
|
// modFile.Cleanup must be called before indexModFile.
|
||||||
func indexModFile(data []byte, modFile *modfile.File, needsFix bool) *modFileIndex {
|
func indexModFile(data []byte, modFile *modfile.File, mod module.Version, needsFix bool) *modFileIndex {
|
||||||
i := new(modFileIndex)
|
i := new(modFileIndex)
|
||||||
i.data = data
|
i.data = data
|
||||||
i.dataNeedsFix = needsFix
|
i.dataNeedsFix = needsFix
|
||||||
|
|
@ -345,12 +363,12 @@ func indexModFile(data []byte, modFile *modfile.File, needsFix bool) *modFileInd
|
||||||
|
|
||||||
i.goVersionV = ""
|
i.goVersionV = ""
|
||||||
if modFile.Go == nil {
|
if modFile.Go == nil {
|
||||||
rawGoVersion.Store(Target, "")
|
rawGoVersion.Store(mod, "")
|
||||||
} else {
|
} else {
|
||||||
// We're going to use the semver package to compare Go versions, so go ahead
|
// We're going to use the semver package to compare Go versions, so go ahead
|
||||||
// and add the "v" prefix it expects once instead of every time.
|
// and add the "v" prefix it expects once instead of every time.
|
||||||
i.goVersionV = "v" + modFile.Go.Version
|
i.goVersionV = "v" + modFile.Go.Version
|
||||||
rawGoVersion.Store(Target, modFile.Go.Version)
|
rawGoVersion.Store(mod, modFile.Go.Version)
|
||||||
}
|
}
|
||||||
|
|
||||||
i.require = make(map[module.Version]requireMeta, len(modFile.Require))
|
i.require = make(map[module.Version]requireMeta, len(modFile.Require))
|
||||||
|
|
@ -490,8 +508,8 @@ type retraction struct {
|
||||||
//
|
//
|
||||||
// The caller must not modify the returned summary.
|
// The caller must not modify the returned summary.
|
||||||
func goModSummary(m module.Version) (*modFileSummary, error) {
|
func goModSummary(m module.Version) (*modFileSummary, error) {
|
||||||
if m == Target {
|
if m.Version == "" && MainModules.Contains(m.Path) {
|
||||||
panic("internal error: goModSummary called on the Target module")
|
panic("internal error: goModSummary called on a main module")
|
||||||
}
|
}
|
||||||
|
|
||||||
if cfg.BuildMod == "vendor" {
|
if cfg.BuildMod == "vendor" {
|
||||||
|
|
@ -506,7 +524,7 @@ func goModSummary(m module.Version) (*modFileSummary, error) {
|
||||||
|
|
||||||
// For every module other than the target,
|
// For every module other than the target,
|
||||||
// return the full list of modules from modules.txt.
|
// return the full list of modules from modules.txt.
|
||||||
readVendorList()
|
readVendorList(MainModules.mustGetSingleMainModule())
|
||||||
|
|
||||||
// We don't know what versions the vendored module actually relies on,
|
// We don't know what versions the vendored module actually relies on,
|
||||||
// so assume that it requires everything.
|
// so assume that it requires everything.
|
||||||
|
|
@ -514,15 +532,15 @@ func goModSummary(m module.Version) (*modFileSummary, error) {
|
||||||
return summary, nil
|
return summary, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
actual := resolveReplacement(m)
|
actual, replacedFrom := resolveReplacement(m)
|
||||||
if HasModRoot() && cfg.BuildMod == "readonly" && actual.Version != "" {
|
if HasModRoot() && cfg.BuildMod == "readonly" && !inWorkspaceMode() && actual.Version != "" {
|
||||||
key := module.Version{Path: actual.Path, Version: actual.Version + "/go.mod"}
|
key := module.Version{Path: actual.Path, Version: actual.Version + "/go.mod"}
|
||||||
if !modfetch.HaveSum(key) {
|
if !modfetch.HaveSum(key) {
|
||||||
suggestion := fmt.Sprintf("; to add it:\n\tgo mod download %s", m.Path)
|
suggestion := fmt.Sprintf("; to add it:\n\tgo mod download %s", m.Path)
|
||||||
return nil, module.VersionError(actual, &sumMissingError{suggestion: suggestion})
|
return nil, module.VersionError(actual, &sumMissingError{suggestion: suggestion})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
summary, err := rawGoModSummary(actual)
|
summary, err := rawGoModSummary(actual, replacedFrom)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -553,27 +571,29 @@ func goModSummary(m module.Version) (*modFileSummary, error) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if index != nil && len(index.exclude) > 0 {
|
for _, mainModule := range MainModules.Versions() {
|
||||||
// Drop any requirements on excluded versions.
|
if index := MainModules.Index(mainModule); index != nil && len(index.exclude) > 0 {
|
||||||
// Don't modify the cached summary though, since we might need the raw
|
// Drop any requirements on excluded versions.
|
||||||
// summary separately.
|
// Don't modify the cached summary though, since we might need the raw
|
||||||
haveExcludedReqs := false
|
// summary separately.
|
||||||
for _, r := range summary.require {
|
haveExcludedReqs := false
|
||||||
if index.exclude[r] {
|
|
||||||
haveExcludedReqs = true
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if haveExcludedReqs {
|
|
||||||
s := new(modFileSummary)
|
|
||||||
*s = *summary
|
|
||||||
s.require = make([]module.Version, 0, len(summary.require))
|
|
||||||
for _, r := range summary.require {
|
for _, r := range summary.require {
|
||||||
if !index.exclude[r] {
|
if index.exclude[r] {
|
||||||
s.require = append(s.require, r)
|
haveExcludedReqs = true
|
||||||
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
summary = s
|
if haveExcludedReqs {
|
||||||
|
s := new(modFileSummary)
|
||||||
|
*s = *summary
|
||||||
|
s.require = make([]module.Version, 0, len(summary.require))
|
||||||
|
for _, r := range summary.require {
|
||||||
|
if !index.exclude[r] {
|
||||||
|
s.require = append(s.require, r)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
summary = s
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return summary, nil
|
return summary, nil
|
||||||
|
|
@ -584,18 +604,23 @@ func goModSummary(m module.Version) (*modFileSummary, error) {
|
||||||
// its dependencies.
|
// its dependencies.
|
||||||
//
|
//
|
||||||
// rawGoModSummary cannot be used on the Target module.
|
// rawGoModSummary cannot be used on the Target module.
|
||||||
func rawGoModSummary(m module.Version) (*modFileSummary, error) {
|
|
||||||
if m == Target {
|
func rawGoModSummary(m module.Version, replacedFrom string) (*modFileSummary, error) {
|
||||||
|
if m.Path == "" && MainModules.Contains(m.Path) {
|
||||||
panic("internal error: rawGoModSummary called on the Target module")
|
panic("internal error: rawGoModSummary called on the Target module")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type key struct {
|
||||||
|
m module.Version
|
||||||
|
replacedFrom string
|
||||||
|
}
|
||||||
type cached struct {
|
type cached struct {
|
||||||
summary *modFileSummary
|
summary *modFileSummary
|
||||||
err error
|
err error
|
||||||
}
|
}
|
||||||
c := rawGoModSummaryCache.Do(m, func() interface{} {
|
c := rawGoModSummaryCache.Do(key{m, replacedFrom}, func() interface{} {
|
||||||
summary := new(modFileSummary)
|
summary := new(modFileSummary)
|
||||||
name, data, err := rawGoModData(m)
|
name, data, err := rawGoModData(m, replacedFrom)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cached{nil, err}
|
return cached{nil, err}
|
||||||
}
|
}
|
||||||
|
|
@ -645,12 +670,15 @@ var rawGoModSummaryCache par.Cache // module.Version → rawGoModSummary result
|
||||||
//
|
//
|
||||||
// Unlike rawGoModSummary, rawGoModData does not cache its results in memory.
|
// Unlike rawGoModSummary, rawGoModData does not cache its results in memory.
|
||||||
// Use rawGoModSummary instead unless you specifically need these bytes.
|
// Use rawGoModSummary instead unless you specifically need these bytes.
|
||||||
func rawGoModData(m module.Version) (name string, data []byte, err error) {
|
func rawGoModData(m module.Version, replacedFrom string) (name string, data []byte, err error) {
|
||||||
if m.Version == "" {
|
if m.Version == "" {
|
||||||
// m is a replacement module with only a file path.
|
// m is a replacement module with only a file path.
|
||||||
dir := m.Path
|
dir := m.Path
|
||||||
if !filepath.IsAbs(dir) {
|
if !filepath.IsAbs(dir) {
|
||||||
dir = filepath.Join(ModRoot(), dir)
|
if replacedFrom == "" {
|
||||||
|
panic(fmt.Errorf("missing module root of main module providing replacement with relative path: %v", dir))
|
||||||
|
}
|
||||||
|
dir = filepath.Join(replacedFrom, dir)
|
||||||
}
|
}
|
||||||
name = filepath.Join(dir, "go.mod")
|
name = filepath.Join(dir, "go.mod")
|
||||||
if gomodActual, ok := fsys.OverlayPath(name); ok {
|
if gomodActual, ok := fsys.OverlayPath(name); ok {
|
||||||
|
|
@ -685,19 +713,20 @@ func rawGoModData(m module.Version) (name string, data []byte, err error) {
|
||||||
//
|
//
|
||||||
// If the queried latest version is replaced,
|
// If the queried latest version is replaced,
|
||||||
// queryLatestVersionIgnoringRetractions returns the replacement.
|
// queryLatestVersionIgnoringRetractions returns the replacement.
|
||||||
func queryLatestVersionIgnoringRetractions(ctx context.Context, path string) (latest module.Version, err error) {
|
func queryLatestVersionIgnoringRetractions(ctx context.Context, path string) (latest module.Version, replacedFrom string, err error) {
|
||||||
type entry struct {
|
type entry struct {
|
||||||
latest module.Version
|
latest module.Version
|
||||||
err error
|
replacedFrom string // if latest is a replacement
|
||||||
|
err error
|
||||||
}
|
}
|
||||||
e := latestVersionIgnoringRetractionsCache.Do(path, func() interface{} {
|
e := latestVersionIgnoringRetractionsCache.Do(path, func() interface{} {
|
||||||
ctx, span := trace.StartSpan(ctx, "queryLatestVersionIgnoringRetractions "+path)
|
ctx, span := trace.StartSpan(ctx, "queryLatestVersionIgnoringRetractions "+path)
|
||||||
defer span.Done()
|
defer span.Done()
|
||||||
|
|
||||||
if repl := Replacement(module.Version{Path: path}); repl.Path != "" {
|
if repl, replFrom := Replacement(module.Version{Path: path}); repl.Path != "" {
|
||||||
// All versions of the module were replaced.
|
// All versions of the module were replaced.
|
||||||
// No need to query.
|
// No need to query.
|
||||||
return &entry{latest: repl}
|
return &entry{latest: repl, replacedFrom: replFrom}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find the latest version of the module.
|
// Find the latest version of the module.
|
||||||
|
|
@ -709,12 +738,12 @@ func queryLatestVersionIgnoringRetractions(ctx context.Context, path string) (la
|
||||||
return &entry{err: err}
|
return &entry{err: err}
|
||||||
}
|
}
|
||||||
latest := module.Version{Path: path, Version: rev.Version}
|
latest := module.Version{Path: path, Version: rev.Version}
|
||||||
if repl := resolveReplacement(latest); repl.Path != "" {
|
if repl, replFrom := resolveReplacement(latest); repl.Path != "" {
|
||||||
latest = repl
|
latest, replacedFrom = repl, replFrom
|
||||||
}
|
}
|
||||||
return &entry{latest: latest}
|
return &entry{latest: latest, replacedFrom: replacedFrom}
|
||||||
}).(*entry)
|
}).(*entry)
|
||||||
return e.latest, e.err
|
return e.latest, e.replacedFrom, e.err
|
||||||
}
|
}
|
||||||
|
|
||||||
var latestVersionIgnoringRetractionsCache par.Cache // path → queryLatestVersionIgnoringRetractions result
|
var latestVersionIgnoringRetractionsCache par.Cache // path → queryLatestVersionIgnoringRetractions result
|
||||||
|
|
|
||||||
|
|
@ -42,7 +42,7 @@ type mvsReqs struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *mvsReqs) Required(mod module.Version) ([]module.Version, error) {
|
func (r *mvsReqs) Required(mod module.Version) ([]module.Version, error) {
|
||||||
if mod == Target {
|
if MainModules.Contains(mod.Path) {
|
||||||
// Use the build list as it existed when r was constructed, not the current
|
// Use the build list as it existed when r was constructed, not the current
|
||||||
// global build list.
|
// global build list.
|
||||||
return r.roots, nil
|
return r.roots, nil
|
||||||
|
|
@ -113,7 +113,7 @@ func versions(ctx context.Context, path string, allowed AllowedFunc) ([]string,
|
||||||
func previousVersion(m module.Version) (module.Version, error) {
|
func previousVersion(m module.Version) (module.Version, error) {
|
||||||
// TODO(golang.org/issue/38714): thread tracing context through MVS.
|
// TODO(golang.org/issue/38714): thread tracing context through MVS.
|
||||||
|
|
||||||
if m == Target {
|
if MainModules.Contains(m.Path) {
|
||||||
return module.Version{Path: m.Path, Version: "none"}, nil
|
return module.Version{Path: m.Path, Version: "none"}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -110,11 +110,12 @@ func queryProxy(ctx context.Context, proxy, path, query, current string, allowed
|
||||||
allowed = func(context.Context, module.Version) error { return nil }
|
allowed = func(context.Context, module.Version) error { return nil }
|
||||||
}
|
}
|
||||||
|
|
||||||
if path == Target.Path && (query == "upgrade" || query == "patch") {
|
if MainModules.Contains(path) && (query == "upgrade" || query == "patch") {
|
||||||
if err := allowed(ctx, Target); err != nil {
|
m := module.Version{Path: path}
|
||||||
|
if err := allowed(ctx, m); err != nil {
|
||||||
return nil, fmt.Errorf("internal error: main module version is not allowed: %w", err)
|
return nil, fmt.Errorf("internal error: main module version is not allowed: %w", err)
|
||||||
}
|
}
|
||||||
return &modfetch.RevInfo{Version: Target.Version}, nil
|
return &modfetch.RevInfo{Version: m.Version}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if path == "std" || path == "cmd" {
|
if path == "std" || path == "cmd" {
|
||||||
|
|
@ -512,9 +513,10 @@ func QueryPackages(ctx context.Context, pattern, query string, current func(stri
|
||||||
pkgMods, modOnly, err := QueryPattern(ctx, pattern, query, current, allowed)
|
pkgMods, modOnly, err := QueryPattern(ctx, pattern, query, current, allowed)
|
||||||
|
|
||||||
if len(pkgMods) == 0 && err == nil {
|
if len(pkgMods) == 0 && err == nil {
|
||||||
|
replacement, _ := Replacement(modOnly.Mod)
|
||||||
return nil, &PackageNotInModuleError{
|
return nil, &PackageNotInModuleError{
|
||||||
Mod: modOnly.Mod,
|
Mod: modOnly.Mod,
|
||||||
Replacement: Replacement(modOnly.Mod),
|
Replacement: replacement,
|
||||||
Query: query,
|
Query: query,
|
||||||
Pattern: pattern,
|
Pattern: pattern,
|
||||||
}
|
}
|
||||||
|
|
@ -551,7 +553,7 @@ func QueryPattern(ctx context.Context, pattern, query string, current func(strin
|
||||||
return m.Errs[0]
|
return m.Errs[0]
|
||||||
}
|
}
|
||||||
|
|
||||||
var match func(mod module.Version, root string, isLocal bool) *search.Match
|
var match func(mod module.Version, roots []string, isLocal bool) *search.Match
|
||||||
matchPattern := search.MatchPattern(pattern)
|
matchPattern := search.MatchPattern(pattern)
|
||||||
|
|
||||||
if i := strings.Index(pattern, "..."); i >= 0 {
|
if i := strings.Index(pattern, "..."); i >= 0 {
|
||||||
|
|
@ -559,30 +561,32 @@ func QueryPattern(ctx context.Context, pattern, query string, current func(strin
|
||||||
if base == "." {
|
if base == "." {
|
||||||
return nil, nil, &WildcardInFirstElementError{Pattern: pattern, Query: query}
|
return nil, nil, &WildcardInFirstElementError{Pattern: pattern, Query: query}
|
||||||
}
|
}
|
||||||
match = func(mod module.Version, root string, isLocal bool) *search.Match {
|
match = func(mod module.Version, roots []string, isLocal bool) *search.Match {
|
||||||
m := search.NewMatch(pattern)
|
m := search.NewMatch(pattern)
|
||||||
matchPackages(ctx, m, imports.AnyTags(), omitStd, []module.Version{mod})
|
matchPackages(ctx, m, imports.AnyTags(), omitStd, []module.Version{mod})
|
||||||
return m
|
return m
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
match = func(mod module.Version, root string, isLocal bool) *search.Match {
|
match = func(mod module.Version, roots []string, isLocal bool) *search.Match {
|
||||||
m := search.NewMatch(pattern)
|
m := search.NewMatch(pattern)
|
||||||
prefix := mod.Path
|
prefix := mod.Path
|
||||||
if mod == Target {
|
if MainModules.Contains(mod.Path) {
|
||||||
prefix = targetPrefix
|
prefix = MainModules.PathPrefix(module.Version{Path: mod.Path})
|
||||||
}
|
}
|
||||||
if _, ok, err := dirInModule(pattern, prefix, root, isLocal); err != nil {
|
for _, root := range roots {
|
||||||
m.AddError(err)
|
if _, ok, err := dirInModule(pattern, prefix, root, isLocal); err != nil {
|
||||||
} else if ok {
|
m.AddError(err)
|
||||||
m.Pkgs = []string{pattern}
|
} else if ok {
|
||||||
|
m.Pkgs = []string{pattern}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return m
|
return m
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var queryMatchesMainModule bool
|
var mainModuleMatches []module.Version
|
||||||
if HasModRoot() {
|
for _, mainModule := range MainModules.Versions() {
|
||||||
m := match(Target, modRoot, true)
|
m := match(mainModule, modRoots, true)
|
||||||
if len(m.Pkgs) > 0 {
|
if len(m.Pkgs) > 0 {
|
||||||
if query != "upgrade" && query != "patch" {
|
if query != "upgrade" && query != "patch" {
|
||||||
return nil, nil, &QueryMatchesPackagesInMainModuleError{
|
return nil, nil, &QueryMatchesPackagesInMainModuleError{
|
||||||
|
|
@ -591,12 +595,12 @@ func QueryPattern(ctx context.Context, pattern, query string, current func(strin
|
||||||
Packages: m.Pkgs,
|
Packages: m.Pkgs,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if err := allowed(ctx, Target); err != nil {
|
if err := allowed(ctx, mainModule); err != nil {
|
||||||
return nil, nil, fmt.Errorf("internal error: package %s is in the main module (%s), but version is not allowed: %w", pattern, Target.Path, err)
|
return nil, nil, fmt.Errorf("internal error: package %s is in the main module (%s), but version is not allowed: %w", pattern, mainModule.Path, err)
|
||||||
}
|
}
|
||||||
return []QueryResult{{
|
return []QueryResult{{
|
||||||
Mod: Target,
|
Mod: mainModule,
|
||||||
Rev: &modfetch.RevInfo{Version: Target.Version},
|
Rev: &modfetch.RevInfo{Version: mainModule.Version},
|
||||||
Packages: m.Pkgs,
|
Packages: m.Pkgs,
|
||||||
}}, nil, nil
|
}}, nil, nil
|
||||||
}
|
}
|
||||||
|
|
@ -604,15 +608,17 @@ func QueryPattern(ctx context.Context, pattern, query string, current func(strin
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if matchPattern(Target.Path) {
|
var matchesMainModule bool
|
||||||
queryMatchesMainModule = true
|
if matchPattern(mainModule.Path) {
|
||||||
|
mainModuleMatches = append(mainModuleMatches, mainModule)
|
||||||
|
matchesMainModule = true
|
||||||
}
|
}
|
||||||
|
|
||||||
if (query == "upgrade" || query == "patch") && queryMatchesMainModule {
|
if (query == "upgrade" || query == "patch") && matchesMainModule {
|
||||||
if err := allowed(ctx, Target); err == nil {
|
if err := allowed(ctx, mainModule); err == nil {
|
||||||
modOnly = &QueryResult{
|
modOnly = &QueryResult{
|
||||||
Mod: Target,
|
Mod: mainModule,
|
||||||
Rev: &modfetch.RevInfo{Version: Target.Version},
|
Rev: &modfetch.RevInfo{Version: mainModule.Version},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -625,16 +631,17 @@ func QueryPattern(ctx context.Context, pattern, query string, current func(strin
|
||||||
if len(candidateModules) == 0 {
|
if len(candidateModules) == 0 {
|
||||||
if modOnly != nil {
|
if modOnly != nil {
|
||||||
return nil, modOnly, nil
|
return nil, modOnly, nil
|
||||||
} else if queryMatchesMainModule {
|
} else if len(mainModuleMatches) != 0 {
|
||||||
return nil, nil, &QueryMatchesMainModuleError{
|
return nil, nil, &QueryMatchesMainModulesError{
|
||||||
Pattern: pattern,
|
MainModules: mainModuleMatches,
|
||||||
Query: query,
|
Pattern: pattern,
|
||||||
|
Query: query,
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return nil, nil, &PackageNotInModuleError{
|
return nil, nil, &PackageNotInModuleError{
|
||||||
Mod: Target,
|
MainModules: mainModuleMatches,
|
||||||
Query: query,
|
Query: query,
|
||||||
Pattern: pattern,
|
Pattern: pattern,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -656,15 +663,16 @@ func QueryPattern(ctx context.Context, pattern, query string, current func(strin
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return r, err
|
return r, err
|
||||||
}
|
}
|
||||||
m := match(r.Mod, root, isLocal)
|
m := match(r.Mod, []string{root}, isLocal)
|
||||||
r.Packages = m.Pkgs
|
r.Packages = m.Pkgs
|
||||||
if len(r.Packages) == 0 && !matchPattern(path) {
|
if len(r.Packages) == 0 && !matchPattern(path) {
|
||||||
if err := firstError(m); err != nil {
|
if err := firstError(m); err != nil {
|
||||||
return r, err
|
return r, err
|
||||||
}
|
}
|
||||||
|
replacement, _ := Replacement(r.Mod)
|
||||||
return r, &PackageNotInModuleError{
|
return r, &PackageNotInModuleError{
|
||||||
Mod: r.Mod,
|
Mod: r.Mod,
|
||||||
Replacement: Replacement(r.Mod),
|
Replacement: replacement,
|
||||||
Query: query,
|
Query: query,
|
||||||
Pattern: pattern,
|
Pattern: pattern,
|
||||||
}
|
}
|
||||||
|
|
@ -684,8 +692,8 @@ func QueryPattern(ctx context.Context, pattern, query string, current func(strin
|
||||||
return err
|
return err
|
||||||
})
|
})
|
||||||
|
|
||||||
if queryMatchesMainModule && len(results) == 0 && modOnly == nil && errors.Is(err, fs.ErrNotExist) {
|
if len(mainModuleMatches) > 0 && len(results) == 0 && modOnly == nil && errors.Is(err, fs.ErrNotExist) {
|
||||||
return nil, nil, &QueryMatchesMainModuleError{
|
return nil, nil, &QueryMatchesMainModulesError{
|
||||||
Pattern: pattern,
|
Pattern: pattern,
|
||||||
Query: query,
|
Query: query,
|
||||||
}
|
}
|
||||||
|
|
@ -701,8 +709,13 @@ func QueryPattern(ctx context.Context, pattern, query string, current func(strin
|
||||||
func modulePrefixesExcludingTarget(path string) []string {
|
func modulePrefixesExcludingTarget(path string) []string {
|
||||||
prefixes := make([]string, 0, strings.Count(path, "/")+1)
|
prefixes := make([]string, 0, strings.Count(path, "/")+1)
|
||||||
|
|
||||||
|
mainModulePrefixes := make(map[string]bool)
|
||||||
|
for _, m := range MainModules.Versions() {
|
||||||
|
mainModulePrefixes[m.Path] = true
|
||||||
|
}
|
||||||
|
|
||||||
for {
|
for {
|
||||||
if path != targetPrefix {
|
if !mainModulePrefixes[path] {
|
||||||
if _, _, ok := module.SplitPathVersion(path); ok {
|
if _, _, ok := module.SplitPathVersion(path); ok {
|
||||||
prefixes = append(prefixes, path)
|
prefixes = append(prefixes, path)
|
||||||
}
|
}
|
||||||
|
|
@ -759,7 +772,7 @@ func queryPrefixModules(ctx context.Context, candidateModules []string, queryMod
|
||||||
case *PackageNotInModuleError:
|
case *PackageNotInModuleError:
|
||||||
// Given the option, prefer to attribute “package not in module”
|
// Given the option, prefer to attribute “package not in module”
|
||||||
// to modules other than the main one.
|
// to modules other than the main one.
|
||||||
if noPackage == nil || noPackage.Mod == Target {
|
if noPackage == nil || MainModules.Contains(noPackage.Mod.Path) {
|
||||||
noPackage = rErr
|
noPackage = rErr
|
||||||
}
|
}
|
||||||
case *NoMatchingVersionError:
|
case *NoMatchingVersionError:
|
||||||
|
|
@ -878,6 +891,7 @@ func (e *WildcardInFirstElementError) Error() string {
|
||||||
// code for the versions it knows about, and thus did not have the opportunity
|
// code for the versions it knows about, and thus did not have the opportunity
|
||||||
// to return a non-400 status code to suppress fallback.
|
// to return a non-400 status code to suppress fallback.
|
||||||
type PackageNotInModuleError struct {
|
type PackageNotInModuleError struct {
|
||||||
|
MainModules []module.Version
|
||||||
Mod module.Version
|
Mod module.Version
|
||||||
Replacement module.Version
|
Replacement module.Version
|
||||||
Query string
|
Query string
|
||||||
|
|
@ -885,11 +899,15 @@ type PackageNotInModuleError struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *PackageNotInModuleError) Error() string {
|
func (e *PackageNotInModuleError) Error() string {
|
||||||
if e.Mod == Target {
|
if len(e.MainModules) > 0 {
|
||||||
if strings.Contains(e.Pattern, "...") {
|
prefix := "workspace modules do"
|
||||||
return fmt.Sprintf("main module (%s) does not contain packages matching %s", Target.Path, e.Pattern)
|
if len(e.MainModules) == 1 {
|
||||||
|
prefix = fmt.Sprintf("main module (%s) does", e.MainModules[0])
|
||||||
}
|
}
|
||||||
return fmt.Sprintf("main module (%s) does not contain package %s", Target.Path, e.Pattern)
|
if strings.Contains(e.Pattern, "...") {
|
||||||
|
return fmt.Sprintf("%s not contain packages matching %s", prefix, e.Pattern)
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("%s not contain package %s", prefix, e.Pattern)
|
||||||
}
|
}
|
||||||
|
|
||||||
found := ""
|
found := ""
|
||||||
|
|
@ -951,7 +969,7 @@ func moduleHasRootPackage(ctx context.Context, m module.Version) (bool, error) {
|
||||||
// we don't need to verify it in go.sum. This makes 'go list -m -u' faster
|
// we don't need to verify it in go.sum. This makes 'go list -m -u' faster
|
||||||
// and simpler.
|
// and simpler.
|
||||||
func versionHasGoMod(_ context.Context, m module.Version) (bool, error) {
|
func versionHasGoMod(_ context.Context, m module.Version) (bool, error) {
|
||||||
_, data, err := rawGoModData(m)
|
_, data, err := rawGoModData(m, "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
|
|
@ -978,14 +996,18 @@ func lookupRepo(proxy, path string) (repo versionRepo, err error) {
|
||||||
repo = emptyRepo{path: path, err: err}
|
repo = emptyRepo{path: path, err: err}
|
||||||
}
|
}
|
||||||
|
|
||||||
if index == nil {
|
// TODO(#45713): Join all the highestReplaced fields into a single value.
|
||||||
return repo, err
|
for _, mm := range MainModules.Versions() {
|
||||||
}
|
index := MainModules.Index(mm)
|
||||||
if _, ok := index.highestReplaced[path]; !ok {
|
if index == nil {
|
||||||
return repo, err
|
continue
|
||||||
|
}
|
||||||
|
if _, ok := index.highestReplaced[path]; ok {
|
||||||
|
return &replacementRepo{repo: repo}, nil
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return &replacementRepo{repo: repo}, nil
|
return repo, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// An emptyRepo is a versionRepo that contains no versions.
|
// An emptyRepo is a versionRepo that contains no versions.
|
||||||
|
|
@ -1024,11 +1046,13 @@ func (rr *replacementRepo) Versions(prefix string) ([]string, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
versions := repoVersions
|
versions := repoVersions
|
||||||
if index != nil && len(index.replace) > 0 {
|
for _, mm := range MainModules.Versions() {
|
||||||
path := rr.ModulePath()
|
if index := MainModules.Index(mm); index != nil && len(index.replace) > 0 {
|
||||||
for m, _ := range index.replace {
|
path := rr.ModulePath()
|
||||||
if m.Path == path && strings.HasPrefix(m.Version, prefix) && m.Version != "" && !module.IsPseudoVersion(m.Version) {
|
for m, _ := range index.replace {
|
||||||
versions = append(versions, m.Version)
|
if m.Path == path && strings.HasPrefix(m.Version, prefix) && m.Version != "" && !module.IsPseudoVersion(m.Version) {
|
||||||
|
versions = append(versions, m.Version)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1046,7 +1070,16 @@ func (rr *replacementRepo) Versions(prefix string) ([]string, error) {
|
||||||
|
|
||||||
func (rr *replacementRepo) Stat(rev string) (*modfetch.RevInfo, error) {
|
func (rr *replacementRepo) Stat(rev string) (*modfetch.RevInfo, error) {
|
||||||
info, err := rr.repo.Stat(rev)
|
info, err := rr.repo.Stat(rev)
|
||||||
if err == nil || index == nil || len(index.replace) == 0 {
|
if err == nil {
|
||||||
|
return info, err
|
||||||
|
}
|
||||||
|
var hasReplacements bool
|
||||||
|
for _, v := range MainModules.Versions() {
|
||||||
|
if index := MainModules.Index(v); index != nil && len(index.replace) > 0 {
|
||||||
|
hasReplacements = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !hasReplacements {
|
||||||
return info, err
|
return info, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1065,7 +1098,7 @@ func (rr *replacementRepo) Stat(rev string) (*modfetch.RevInfo, error) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if r := Replacement(module.Version{Path: path, Version: v}); r.Path == "" {
|
if r, _ := Replacement(module.Version{Path: path, Version: v}); r.Path == "" {
|
||||||
return info, err
|
return info, err
|
||||||
}
|
}
|
||||||
return rr.replacementStat(v)
|
return rr.replacementStat(v)
|
||||||
|
|
@ -1073,27 +1106,42 @@ func (rr *replacementRepo) Stat(rev string) (*modfetch.RevInfo, error) {
|
||||||
|
|
||||||
func (rr *replacementRepo) Latest() (*modfetch.RevInfo, error) {
|
func (rr *replacementRepo) Latest() (*modfetch.RevInfo, error) {
|
||||||
info, err := rr.repo.Latest()
|
info, err := rr.repo.Latest()
|
||||||
|
path := rr.ModulePath()
|
||||||
|
|
||||||
if index != nil {
|
highestReplaced, found := "", false
|
||||||
path := rr.ModulePath()
|
for _, mm := range MainModules.Versions() {
|
||||||
if v, ok := index.highestReplaced[path]; ok {
|
if index := MainModules.Index(mm); index != nil {
|
||||||
if v == "" {
|
if v, ok := index.highestReplaced[path]; ok {
|
||||||
// The only replacement is a wildcard that doesn't specify a version, so
|
if !found {
|
||||||
// synthesize a pseudo-version with an appropriate major version and a
|
highestReplaced, found = v, true
|
||||||
// timestamp below any real timestamp. That way, if the main module is
|
continue
|
||||||
// used from within some other module, the user will be able to upgrade
|
}
|
||||||
// the requirement to any real version they choose.
|
if semver.Compare(v, highestReplaced) > 0 {
|
||||||
if _, pathMajor, ok := module.SplitPathVersion(path); ok && len(pathMajor) > 0 {
|
highestReplaced = v
|
||||||
v = module.PseudoVersion(pathMajor[1:], "", time.Time{}, "000000000000")
|
|
||||||
} else {
|
|
||||||
v = module.PseudoVersion("v0", "", time.Time{}, "000000000000")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if err != nil || semver.Compare(v, info.Version) > 0 {
|
if found {
|
||||||
return rr.replacementStat(v)
|
v := highestReplaced
|
||||||
|
|
||||||
|
if v == "" {
|
||||||
|
// The only replacement is a wildcard that doesn't specify a version, so
|
||||||
|
// synthesize a pseudo-version with an appropriate major version and a
|
||||||
|
// timestamp below any real timestamp. That way, if the main module is
|
||||||
|
// used from within some other module, the user will be able to upgrade
|
||||||
|
// the requirement to any real version they choose.
|
||||||
|
if _, pathMajor, ok := module.SplitPathVersion(path); ok && len(pathMajor) > 0 {
|
||||||
|
v = module.PseudoVersion(pathMajor[1:], "", time.Time{}, "000000000000")
|
||||||
|
} else {
|
||||||
|
v = module.PseudoVersion("v0", "", time.Time{}, "000000000000")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err != nil || semver.Compare(v, info.Version) > 0 {
|
||||||
|
return rr.replacementStat(v)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return info, err
|
return info, err
|
||||||
|
|
@ -1108,20 +1156,46 @@ func (rr *replacementRepo) replacementStat(v string) (*modfetch.RevInfo, error)
|
||||||
return rev, nil
|
return rev, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// A QueryMatchesMainModuleError indicates that a query requests
|
// A QueryMatchesMainModulesError indicates that a query requests
|
||||||
// a version of the main module that cannot be satisfied.
|
// a version of the main module that cannot be satisfied.
|
||||||
// (The main module's version cannot be changed.)
|
// (The main module's version cannot be changed.)
|
||||||
type QueryMatchesMainModuleError struct {
|
type QueryMatchesMainModulesError struct {
|
||||||
Pattern string
|
MainModules []module.Version
|
||||||
Query string
|
Pattern string
|
||||||
|
Query string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *QueryMatchesMainModuleError) Error() string {
|
func (e *QueryMatchesMainModulesError) Error() string {
|
||||||
if e.Pattern == Target.Path {
|
if MainModules.Contains(e.Pattern) {
|
||||||
return fmt.Sprintf("can't request version %q of the main module (%s)", e.Query, e.Pattern)
|
return fmt.Sprintf("can't request version %q of the main module (%s)", e.Query, e.Pattern)
|
||||||
}
|
}
|
||||||
|
|
||||||
return fmt.Sprintf("can't request version %q of pattern %q that includes the main module (%s)", e.Query, e.Pattern, Target.Path)
|
plural := ""
|
||||||
|
mainModulePaths := make([]string, len(e.MainModules))
|
||||||
|
for i := range e.MainModules {
|
||||||
|
mainModulePaths[i] = e.MainModules[i].Path
|
||||||
|
}
|
||||||
|
if len(e.MainModules) > 1 {
|
||||||
|
plural = "s"
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("can't request version %q of pattern %q that includes the main module%s (%s)", e.Query, e.Pattern, plural, strings.Join(mainModulePaths, ", "))
|
||||||
|
}
|
||||||
|
|
||||||
|
// A QueryUpgradesAllError indicates that a query requests
|
||||||
|
// an upgrade on the all pattern.
|
||||||
|
// (The main module's version cannot be changed.)
|
||||||
|
type QueryUpgradesAllError struct {
|
||||||
|
MainModules []module.Version
|
||||||
|
Query string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *QueryUpgradesAllError) Error() string {
|
||||||
|
var plural string = ""
|
||||||
|
if len(e.MainModules) != 1 {
|
||||||
|
plural = "s"
|
||||||
|
}
|
||||||
|
|
||||||
|
return fmt.Sprintf("can't request version %q of pattern \"all\" that includes the main module%s", e.Query, plural)
|
||||||
}
|
}
|
||||||
|
|
||||||
// A QueryMatchesPackagesInMainModuleError indicates that a query cannot be
|
// A QueryMatchesPackagesInMainModuleError indicates that a query cannot be
|
||||||
|
|
|
||||||
|
|
@ -131,9 +131,10 @@ func matchPackages(ctx context.Context, m *search.Match, tags map[string]bool, f
|
||||||
}
|
}
|
||||||
|
|
||||||
if cfg.BuildMod == "vendor" {
|
if cfg.BuildMod == "vendor" {
|
||||||
if HasModRoot() {
|
mod := MainModules.mustGetSingleMainModule()
|
||||||
walkPkgs(ModRoot(), targetPrefix, pruneGoMod|pruneVendor)
|
if modRoot := MainModules.ModRoot(mod); modRoot != "" {
|
||||||
walkPkgs(filepath.Join(ModRoot(), "vendor"), "", pruneVendor)
|
walkPkgs(modRoot, MainModules.PathPrefix(mod), pruneGoMod|pruneVendor)
|
||||||
|
walkPkgs(filepath.Join(modRoot, "vendor"), "", pruneVendor)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
@ -147,12 +148,12 @@ func matchPackages(ctx context.Context, m *search.Match, tags map[string]bool, f
|
||||||
root, modPrefix string
|
root, modPrefix string
|
||||||
isLocal bool
|
isLocal bool
|
||||||
)
|
)
|
||||||
if mod == Target {
|
if MainModules.Contains(mod.Path) {
|
||||||
if !HasModRoot() {
|
if MainModules.ModRoot(mod) == "" {
|
||||||
continue // If there is no main module, we can't search in it.
|
continue // If there is no main module, we can't search in it.
|
||||||
}
|
}
|
||||||
root = ModRoot()
|
root = MainModules.ModRoot(mod)
|
||||||
modPrefix = targetPrefix
|
modPrefix = MainModules.PathPrefix(mod)
|
||||||
isLocal = true
|
isLocal = true
|
||||||
} else {
|
} else {
|
||||||
var err error
|
var err error
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@ import (
|
||||||
|
|
||||||
"cmd/go/internal/base"
|
"cmd/go/internal/base"
|
||||||
|
|
||||||
|
"golang.org/x/mod/modfile"
|
||||||
"golang.org/x/mod/module"
|
"golang.org/x/mod/module"
|
||||||
"golang.org/x/mod/semver"
|
"golang.org/x/mod/semver"
|
||||||
)
|
)
|
||||||
|
|
@ -35,13 +36,13 @@ type vendorMetadata struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// readVendorList reads the list of vendored modules from vendor/modules.txt.
|
// readVendorList reads the list of vendored modules from vendor/modules.txt.
|
||||||
func readVendorList() {
|
func readVendorList(mainModule module.Version) {
|
||||||
vendorOnce.Do(func() {
|
vendorOnce.Do(func() {
|
||||||
vendorList = nil
|
vendorList = nil
|
||||||
vendorPkgModule = make(map[string]module.Version)
|
vendorPkgModule = make(map[string]module.Version)
|
||||||
vendorVersion = make(map[string]string)
|
vendorVersion = make(map[string]string)
|
||||||
vendorMeta = make(map[module.Version]vendorMetadata)
|
vendorMeta = make(map[module.Version]vendorMetadata)
|
||||||
data, err := os.ReadFile(filepath.Join(ModRoot(), "vendor/modules.txt"))
|
data, err := os.ReadFile(filepath.Join(MainModules.ModRoot(mainModule), "vendor/modules.txt"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if !errors.Is(err, fs.ErrNotExist) {
|
if !errors.Is(err, fs.ErrNotExist) {
|
||||||
base.Fatalf("go: %s", err)
|
base.Fatalf("go: %s", err)
|
||||||
|
|
@ -134,8 +135,8 @@ func readVendorList() {
|
||||||
// checkVendorConsistency verifies that the vendor/modules.txt file matches (if
|
// checkVendorConsistency verifies that the vendor/modules.txt file matches (if
|
||||||
// go 1.14) or at least does not contradict (go 1.13 or earlier) the
|
// go 1.14) or at least does not contradict (go 1.13 or earlier) the
|
||||||
// requirements and replacements listed in the main module's go.mod file.
|
// requirements and replacements listed in the main module's go.mod file.
|
||||||
func checkVendorConsistency() {
|
func checkVendorConsistency(index *modFileIndex, modFile *modfile.File) {
|
||||||
readVendorList()
|
readVendorList(MainModules.mustGetSingleMainModule())
|
||||||
|
|
||||||
pre114 := false
|
pre114 := false
|
||||||
if semver.Compare(index.goVersionV, "v1.14") < 0 {
|
if semver.Compare(index.goVersionV, "v1.14") < 0 {
|
||||||
|
|
@ -208,7 +209,7 @@ func checkVendorConsistency() {
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, mod := range vendorReplaced {
|
for _, mod := range vendorReplaced {
|
||||||
r := Replacement(mod)
|
r, _ := Replacement(mod)
|
||||||
if r == (module.Version{}) {
|
if r == (module.Version{}) {
|
||||||
vendErrorf(mod, "is marked as replaced in vendor/modules.txt, but not replaced in go.mod")
|
vendErrorf(mod, "is marked as replaced in vendor/modules.txt, but not replaced in go.mod")
|
||||||
continue
|
continue
|
||||||
|
|
@ -219,6 +220,7 @@ func checkVendorConsistency() {
|
||||||
}
|
}
|
||||||
|
|
||||||
if vendErrors.Len() > 0 {
|
if vendErrors.Len() > 0 {
|
||||||
|
modRoot := MainModules.ModRoot(MainModules.mustGetSingleMainModule())
|
||||||
base.Fatalf("go: inconsistent vendoring in %s:%s\n\n\tTo ignore the vendor directory, use -mod=readonly or -mod=mod.\n\tTo sync the vendor directory, run:\n\t\tgo mod vendor", modRoot, vendErrors)
|
base.Fatalf("go: inconsistent vendoring in %s:%s\n\n\tTo ignore the vendor directory, use -mod=readonly or -mod=mod.\n\tTo sync the vendor directory, run:\n\t\tgo mod vendor", modRoot, vendErrors)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ package mvs
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"reflect"
|
||||||
"sort"
|
"sort"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
|
|
@ -85,11 +86,11 @@ type DowngradeReqs interface {
|
||||||
// of the list are sorted by path.
|
// of the list are sorted by path.
|
||||||
//
|
//
|
||||||
// See https://research.swtch.com/vgo-mvs for details.
|
// See https://research.swtch.com/vgo-mvs for details.
|
||||||
func BuildList(target module.Version, reqs Reqs) ([]module.Version, error) {
|
func BuildList(targets []module.Version, reqs Reqs) ([]module.Version, error) {
|
||||||
return buildList(target, reqs, nil)
|
return buildList(targets, reqs, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
func buildList(target module.Version, reqs Reqs, upgrade func(module.Version) (module.Version, error)) ([]module.Version, error) {
|
func buildList(targets []module.Version, reqs Reqs, upgrade func(module.Version) (module.Version, error)) ([]module.Version, error) {
|
||||||
cmp := func(v1, v2 string) int {
|
cmp := func(v1, v2 string) int {
|
||||||
if reqs.Max(v1, v2) != v1 {
|
if reqs.Max(v1, v2) != v1 {
|
||||||
return -1
|
return -1
|
||||||
|
|
@ -102,7 +103,7 @@ func buildList(target module.Version, reqs Reqs, upgrade func(module.Version) (m
|
||||||
|
|
||||||
var (
|
var (
|
||||||
mu sync.Mutex
|
mu sync.Mutex
|
||||||
g = NewGraph(cmp, []module.Version{target})
|
g = NewGraph(cmp, targets)
|
||||||
upgrades = map[module.Version]module.Version{}
|
upgrades = map[module.Version]module.Version{}
|
||||||
errs = map[module.Version]error{} // (non-nil errors only)
|
errs = map[module.Version]error{} // (non-nil errors only)
|
||||||
)
|
)
|
||||||
|
|
@ -110,7 +111,9 @@ func buildList(target module.Version, reqs Reqs, upgrade func(module.Version) (m
|
||||||
// Explore work graph in parallel in case reqs.Required
|
// Explore work graph in parallel in case reqs.Required
|
||||||
// does high-latency network operations.
|
// does high-latency network operations.
|
||||||
var work par.Work
|
var work par.Work
|
||||||
work.Add(target)
|
for _, target := range targets {
|
||||||
|
work.Add(target)
|
||||||
|
}
|
||||||
work.Do(10, func(item interface{}) {
|
work.Do(10, func(item interface{}) {
|
||||||
m := item.(module.Version)
|
m := item.(module.Version)
|
||||||
|
|
||||||
|
|
@ -168,12 +171,12 @@ func buildList(target module.Version, reqs Reqs, upgrade func(module.Version) (m
|
||||||
|
|
||||||
// The final list is the minimum version of each module found in the graph.
|
// The final list is the minimum version of each module found in the graph.
|
||||||
list := g.BuildList()
|
list := g.BuildList()
|
||||||
if v := list[0]; v != target {
|
if vs := list[:len(targets)]; !reflect.DeepEqual(vs, targets) {
|
||||||
// target.Version will be "" for modload, the main client of MVS.
|
// target.Version will be "" for modload, the main client of MVS.
|
||||||
// "" denotes the main module, which has no version. However, MVS treats
|
// "" denotes the main module, which has no version. However, MVS treats
|
||||||
// version strings as opaque, so "" is not a special value here.
|
// version strings as opaque, so "" is not a special value here.
|
||||||
// See golang.org/issue/31491, golang.org/issue/29773.
|
// See golang.org/issue/31491, golang.org/issue/29773.
|
||||||
panic(fmt.Sprintf("mistake: chose version %q instead of target %+v", v, target))
|
panic(fmt.Sprintf("mistake: chose versions %+v instead of targets %+v", vs, targets))
|
||||||
}
|
}
|
||||||
return list, nil
|
return list, nil
|
||||||
}
|
}
|
||||||
|
|
@ -181,8 +184,8 @@ func buildList(target module.Version, reqs Reqs, upgrade func(module.Version) (m
|
||||||
// Req returns the minimal requirement list for the target module,
|
// Req returns the minimal requirement list for the target module,
|
||||||
// with the constraint that all module paths listed in base must
|
// with the constraint that all module paths listed in base must
|
||||||
// appear in the returned list.
|
// appear in the returned list.
|
||||||
func Req(target module.Version, base []string, reqs Reqs) ([]module.Version, error) {
|
func Req(mainModule module.Version, base []string, reqs Reqs) ([]module.Version, error) {
|
||||||
list, err := BuildList(target, reqs)
|
list, err := BuildList([]module.Version{mainModule}, reqs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -194,7 +197,8 @@ func Req(target module.Version, base []string, reqs Reqs) ([]module.Version, err
|
||||||
// Compute postorder, cache requirements.
|
// Compute postorder, cache requirements.
|
||||||
var postorder []module.Version
|
var postorder []module.Version
|
||||||
reqCache := map[module.Version][]module.Version{}
|
reqCache := map[module.Version][]module.Version{}
|
||||||
reqCache[target] = nil
|
reqCache[mainModule] = nil
|
||||||
|
|
||||||
var walk func(module.Version) error
|
var walk func(module.Version) error
|
||||||
walk = func(m module.Version) error {
|
walk = func(m module.Version) error {
|
||||||
_, ok := reqCache[m]
|
_, ok := reqCache[m]
|
||||||
|
|
@ -273,7 +277,7 @@ func Req(target module.Version, base []string, reqs Reqs) ([]module.Version, err
|
||||||
// UpgradeAll returns a build list for the target module
|
// UpgradeAll returns a build list for the target module
|
||||||
// in which every module is upgraded to its latest version.
|
// in which every module is upgraded to its latest version.
|
||||||
func UpgradeAll(target module.Version, reqs UpgradeReqs) ([]module.Version, error) {
|
func UpgradeAll(target module.Version, reqs UpgradeReqs) ([]module.Version, error) {
|
||||||
return buildList(target, reqs, func(m module.Version) (module.Version, error) {
|
return buildList([]module.Version{target}, reqs, func(m module.Version) (module.Version, error) {
|
||||||
if m.Path == target.Path {
|
if m.Path == target.Path {
|
||||||
return target, nil
|
return target, nil
|
||||||
}
|
}
|
||||||
|
|
@ -308,7 +312,7 @@ func Upgrade(target module.Version, reqs UpgradeReqs, upgrade ...module.Version)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return buildList(target, &override{target, list, reqs}, func(m module.Version) (module.Version, error) {
|
return buildList([]module.Version{target}, &override{target, list, reqs}, func(m module.Version) (module.Version, error) {
|
||||||
if v, ok := upgradeTo[m.Path]; ok {
|
if v, ok := upgradeTo[m.Path]; ok {
|
||||||
return module.Version{Path: m.Path, Version: v}, nil
|
return module.Version{Path: m.Path, Version: v}, nil
|
||||||
}
|
}
|
||||||
|
|
@ -331,7 +335,7 @@ func Downgrade(target module.Version, reqs DowngradeReqs, downgrade ...module.Ve
|
||||||
//
|
//
|
||||||
// In order to generate those new requirements, we need to identify versions
|
// In order to generate those new requirements, we need to identify versions
|
||||||
// for every module in the build list — not just reqs.Required(target).
|
// for every module in the build list — not just reqs.Required(target).
|
||||||
list, err := BuildList(target, reqs)
|
list, err := BuildList([]module.Version{target}, reqs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -446,7 +450,7 @@ List:
|
||||||
// list with the actual versions of the downgraded modules as selected by MVS,
|
// list with the actual versions of the downgraded modules as selected by MVS,
|
||||||
// instead of our initial downgrades.
|
// instead of our initial downgrades.
|
||||||
// (See the downhiddenartifact and downhiddencross test cases).
|
// (See the downhiddenartifact and downhiddencross test cases).
|
||||||
actual, err := BuildList(target, &override{
|
actual, err := BuildList([]module.Version{target}, &override{
|
||||||
target: target,
|
target: target,
|
||||||
list: downgraded,
|
list: downgraded,
|
||||||
Reqs: reqs,
|
Reqs: reqs,
|
||||||
|
|
@ -466,7 +470,7 @@ List:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return BuildList(target, &override{
|
return BuildList([]module.Version{target}, &override{
|
||||||
target: target,
|
target: target,
|
||||||
list: downgraded,
|
list: downgraded,
|
||||||
Reqs: reqs,
|
Reqs: reqs,
|
||||||
|
|
|
||||||
|
|
@ -507,7 +507,7 @@ func Test(t *testing.T) {
|
||||||
t.Fatalf("build takes one argument: %q", line)
|
t.Fatalf("build takes one argument: %q", line)
|
||||||
}
|
}
|
||||||
fns = append(fns, func(t *testing.T) {
|
fns = append(fns, func(t *testing.T) {
|
||||||
list, err := BuildList(m(kf[1]), reqs)
|
list, err := BuildList([]module.Version{m(kf[1])}, reqs)
|
||||||
checkList(t, key, list, err, val)
|
checkList(t, key, list, err, val)
|
||||||
})
|
})
|
||||||
continue
|
continue
|
||||||
|
|
|
||||||
|
|
@ -65,6 +65,7 @@ func init() {
|
||||||
CmdRun.Run = runRun // break init loop
|
CmdRun.Run = runRun // break init loop
|
||||||
|
|
||||||
work.AddBuildFlags(CmdRun, work.DefaultBuildFlags)
|
work.AddBuildFlags(CmdRun, work.DefaultBuildFlags)
|
||||||
|
base.AddWorkfileFlag(&CmdRun.Flag)
|
||||||
CmdRun.Flag.Var((*base.StringsFlag)(&work.ExecCmd), "exec", "")
|
CmdRun.Flag.Var((*base.StringsFlag)(&work.ExecCmd), "exec", "")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -73,6 +74,8 @@ func printStderr(args ...interface{}) (int, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func runRun(ctx context.Context, cmd *base.Command, args []string) {
|
func runRun(ctx context.Context, cmd *base.Command, args []string) {
|
||||||
|
modload.InitWorkfile()
|
||||||
|
|
||||||
if shouldUseOutsideModuleMode(args) {
|
if shouldUseOutsideModuleMode(args) {
|
||||||
// Set global module flags for 'go run cmd@version'.
|
// Set global module flags for 'go run cmd@version'.
|
||||||
// This must be done before modload.Init, but we need to call work.BuildInit
|
// This must be done before modload.Init, but we need to call work.BuildInit
|
||||||
|
|
|
||||||
|
|
@ -202,12 +202,6 @@ func (m *Match) MatchPackages() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var modRoot string
|
|
||||||
|
|
||||||
func SetModRoot(dir string) {
|
|
||||||
modRoot = dir
|
|
||||||
}
|
|
||||||
|
|
||||||
// MatchDirs sets m.Dirs to a non-nil slice containing all directories that
|
// MatchDirs sets m.Dirs to a non-nil slice containing all directories that
|
||||||
// potentially match a local pattern. The pattern must begin with an absolute
|
// potentially match a local pattern. The pattern must begin with an absolute
|
||||||
// path, or "./", or "../". On Windows, the pattern may use slash or backslash
|
// path, or "./", or "../". On Windows, the pattern may use slash or backslash
|
||||||
|
|
@ -215,7 +209,7 @@ func SetModRoot(dir string) {
|
||||||
//
|
//
|
||||||
// If any errors may have caused the set of directories to be incomplete,
|
// If any errors may have caused the set of directories to be incomplete,
|
||||||
// MatchDirs appends those errors to m.Errs.
|
// MatchDirs appends those errors to m.Errs.
|
||||||
func (m *Match) MatchDirs() {
|
func (m *Match) MatchDirs(modRoots []string) {
|
||||||
m.Dirs = []string{}
|
m.Dirs = []string{}
|
||||||
if !m.IsLocal() {
|
if !m.IsLocal() {
|
||||||
m.AddError(fmt.Errorf("internal error: MatchDirs: %s is not a valid filesystem pattern", m.pattern))
|
m.AddError(fmt.Errorf("internal error: MatchDirs: %s is not a valid filesystem pattern", m.pattern))
|
||||||
|
|
@ -253,15 +247,24 @@ func (m *Match) MatchDirs() {
|
||||||
// We need to preserve the ./ for pattern matching
|
// We need to preserve the ./ for pattern matching
|
||||||
// and in the returned import paths.
|
// and in the returned import paths.
|
||||||
|
|
||||||
if modRoot != "" {
|
if len(modRoots) > 1 {
|
||||||
abs, err := filepath.Abs(dir)
|
abs, err := filepath.Abs(dir)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
m.AddError(err)
|
m.AddError(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if !hasFilepathPrefix(abs, modRoot) {
|
var found bool
|
||||||
m.AddError(fmt.Errorf("directory %s is outside module root (%s)", abs, modRoot))
|
for _, modRoot := range modRoots {
|
||||||
return
|
if modRoot != "" && hasFilepathPrefix(abs, modRoot) {
|
||||||
|
found = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !found {
|
||||||
|
plural := ""
|
||||||
|
if len(modRoots) > 1 {
|
||||||
|
plural = "s"
|
||||||
|
}
|
||||||
|
m.AddError(fmt.Errorf("directory %s is outside module root%s (%s)", abs, plural, strings.Join(modRoots, ", ")))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -424,19 +427,19 @@ func WarnUnmatched(matches []*Match) {
|
||||||
|
|
||||||
// ImportPaths returns the matching paths to use for the given command line.
|
// ImportPaths returns the matching paths to use for the given command line.
|
||||||
// It calls ImportPathsQuiet and then WarnUnmatched.
|
// It calls ImportPathsQuiet and then WarnUnmatched.
|
||||||
func ImportPaths(patterns []string) []*Match {
|
func ImportPaths(patterns, modRoots []string) []*Match {
|
||||||
matches := ImportPathsQuiet(patterns)
|
matches := ImportPathsQuiet(patterns, modRoots)
|
||||||
WarnUnmatched(matches)
|
WarnUnmatched(matches)
|
||||||
return matches
|
return matches
|
||||||
}
|
}
|
||||||
|
|
||||||
// ImportPathsQuiet is like ImportPaths but does not warn about patterns with no matches.
|
// ImportPathsQuiet is like ImportPaths but does not warn about patterns with no matches.
|
||||||
func ImportPathsQuiet(patterns []string) []*Match {
|
func ImportPathsQuiet(patterns, modRoots []string) []*Match {
|
||||||
var out []*Match
|
var out []*Match
|
||||||
for _, a := range CleanPatterns(patterns) {
|
for _, a := range CleanPatterns(patterns) {
|
||||||
m := NewMatch(a)
|
m := NewMatch(a)
|
||||||
if m.IsLocal() {
|
if m.IsLocal() {
|
||||||
m.MatchDirs()
|
m.MatchDirs(modRoots)
|
||||||
|
|
||||||
// Change the file import path to a regular import path if the package
|
// Change the file import path to a regular import path if the package
|
||||||
// is in GOPATH or GOROOT. We don't report errors here; LoadImport
|
// is in GOPATH or GOROOT. We don't report errors here; LoadImport
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,7 @@ import (
|
||||||
"cmd/go/internal/cfg"
|
"cmd/go/internal/cfg"
|
||||||
"cmd/go/internal/load"
|
"cmd/go/internal/load"
|
||||||
"cmd/go/internal/lockedfile"
|
"cmd/go/internal/lockedfile"
|
||||||
|
"cmd/go/internal/modload"
|
||||||
"cmd/go/internal/search"
|
"cmd/go/internal/search"
|
||||||
"cmd/go/internal/trace"
|
"cmd/go/internal/trace"
|
||||||
"cmd/go/internal/work"
|
"cmd/go/internal/work"
|
||||||
|
|
@ -582,6 +583,7 @@ var defaultVetFlags = []string{
|
||||||
}
|
}
|
||||||
|
|
||||||
func runTest(ctx context.Context, cmd *base.Command, args []string) {
|
func runTest(ctx context.Context, cmd *base.Command, args []string) {
|
||||||
|
modload.InitWorkfile()
|
||||||
pkgArgs, testArgs = testFlags(args)
|
pkgArgs, testArgs = testFlags(args)
|
||||||
|
|
||||||
if cfg.DebugTrace != "" {
|
if cfg.DebugTrace != "" {
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,7 @@ import (
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
work.AddBuildFlags(CmdTest, work.OmitVFlag)
|
work.AddBuildFlags(CmdTest, work.OmitVFlag)
|
||||||
|
base.AddWorkfileFlag(&CmdTest.Flag)
|
||||||
|
|
||||||
cf := CmdTest.Flag
|
cf := CmdTest.Flag
|
||||||
cf.BoolVar(&testC, "c", false, "")
|
cf.BoolVar(&testC, "c", false, "")
|
||||||
|
|
|
||||||
|
|
@ -121,6 +121,14 @@ and test commands:
|
||||||
directory, but it is not accessed. When -modfile is specified, an
|
directory, but it is not accessed. When -modfile is specified, an
|
||||||
alternate go.sum file is also used: its path is derived from the
|
alternate go.sum file is also used: its path is derived from the
|
||||||
-modfile flag by trimming the ".mod" extension and appending ".sum".
|
-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
|
-overlay file
|
||||||
read a JSON config file that provides an overlay for build operations.
|
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
|
The file is a JSON struct with a single field, named 'Replace', that
|
||||||
|
|
@ -201,6 +209,7 @@ func init() {
|
||||||
|
|
||||||
AddBuildFlags(CmdBuild, DefaultBuildFlags)
|
AddBuildFlags(CmdBuild, DefaultBuildFlags)
|
||||||
AddBuildFlags(CmdInstall, DefaultBuildFlags)
|
AddBuildFlags(CmdInstall, DefaultBuildFlags)
|
||||||
|
base.AddWorkfileFlag(&CmdBuild.Flag)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Note that flags consulted by other parts of the code
|
// Note that flags consulted by other parts of the code
|
||||||
|
|
@ -364,6 +373,7 @@ var pkgsFilter = func(pkgs []*load.Package) []*load.Package { return pkgs }
|
||||||
var runtimeVersion = runtime.Version()
|
var runtimeVersion = runtime.Version()
|
||||||
|
|
||||||
func runBuild(ctx context.Context, cmd *base.Command, args []string) {
|
func runBuild(ctx context.Context, cmd *base.Command, args []string) {
|
||||||
|
modload.InitWorkfile()
|
||||||
BuildInit()
|
BuildInit()
|
||||||
var b Builder
|
var b Builder
|
||||||
b.Init()
|
b.Init()
|
||||||
|
|
|
||||||
35
src/cmd/go/testdata/script/mod_list_command_line_arguments.txt
vendored
Normal file
35
src/cmd/go/testdata/script/mod_list_command_line_arguments.txt
vendored
Normal file
|
|
@ -0,0 +1,35 @@
|
||||||
|
# The command-line-arguments package does not belong to a module...
|
||||||
|
cd a
|
||||||
|
go list -f '{{.Module}}' ../b/b.go
|
||||||
|
stdout '^<nil>$'
|
||||||
|
|
||||||
|
# ... even if the arguments are sources from that module
|
||||||
|
go list -f '{{.Module}}' a.go
|
||||||
|
stdout '^<nil>$'
|
||||||
|
|
||||||
|
[short] skip
|
||||||
|
|
||||||
|
# check that the version of command-line-arguments doesn't include a module
|
||||||
|
go build -o a.exe a.go
|
||||||
|
go version -m a.exe
|
||||||
|
stdout '^\tpath\tcommand-line-arguments$'
|
||||||
|
stdout '^\tdep\ta\t\(devel\)\t$'
|
||||||
|
! stdout mod
|
||||||
|
|
||||||
|
-- a/go.mod --
|
||||||
|
module a
|
||||||
|
go 1.17
|
||||||
|
-- a/a.go --
|
||||||
|
package main
|
||||||
|
|
||||||
|
import "a/dep"
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
dep.D()
|
||||||
|
}
|
||||||
|
-- a/dep/dep.go --
|
||||||
|
package dep
|
||||||
|
|
||||||
|
func D() {}
|
||||||
|
-- b/b.go --
|
||||||
|
package b
|
||||||
2
src/cmd/go/testdata/script/mod_outside.txt
vendored
2
src/cmd/go/testdata/script/mod_outside.txt
vendored
|
|
@ -251,7 +251,7 @@ stdout 'using example.com/version v1.0.1'
|
||||||
# outside std.
|
# outside std.
|
||||||
go run ./stdonly/stdonly.go
|
go run ./stdonly/stdonly.go
|
||||||
stdout 'path is command-line-arguments$'
|
stdout 'path is command-line-arguments$'
|
||||||
stdout 'main is command-line-arguments \(devel\)'
|
stdout 'main is $'
|
||||||
|
|
||||||
# 'go generate' should work with file arguments.
|
# 'go generate' should work with file arguments.
|
||||||
[exec:touch] go generate ./needmod/needmod.go
|
[exec:touch] go generate ./needmod/needmod.go
|
||||||
|
|
|
||||||
2
src/cmd/go/testdata/script/modfile_flag.txt
vendored
2
src/cmd/go/testdata/script/modfile_flag.txt
vendored
|
|
@ -78,7 +78,7 @@ cmp go.mod go.mod.orig
|
||||||
cmp go.sum go.sum.orig
|
cmp go.sum go.sum.orig
|
||||||
|
|
||||||
|
|
||||||
# If the altnernate mod file does not have a ".mod" suffix, an error
|
# If the alternate mod file does not have a ".mod" suffix, an error
|
||||||
# should be reported.
|
# should be reported.
|
||||||
cp go.alt.mod goaltmod
|
cp go.alt.mod goaltmod
|
||||||
! go mod tidy -modfile=goaltmod
|
! go mod tidy -modfile=goaltmod
|
||||||
|
|
|
||||||
7
src/cmd/go/testdata/script/version.txt
vendored
7
src/cmd/go/testdata/script/version.txt
vendored
|
|
@ -28,6 +28,13 @@ go version -m fortune.exe
|
||||||
stdout '^\tpath\trsc.io/fortune'
|
stdout '^\tpath\trsc.io/fortune'
|
||||||
stdout '^\tmod\trsc.io/fortune\tv1.0.0'
|
stdout '^\tmod\trsc.io/fortune\tv1.0.0'
|
||||||
|
|
||||||
|
# Check the build info of a binary built from $GOROOT/src/cmd
|
||||||
|
go build -o test2json.exe cmd/test2json
|
||||||
|
go version -m test2json.exe
|
||||||
|
stdout '^test2json.exe: .+'
|
||||||
|
stdout '^\tpath\tcmd/test2json$'
|
||||||
|
! stdout 'mod'
|
||||||
|
|
||||||
# Repeat the test with -buildmode=pie.
|
# Repeat the test with -buildmode=pie.
|
||||||
[!buildmode:pie] stop
|
[!buildmode:pie] stop
|
||||||
go build -buildmode=pie -o external.exe rsc.io/fortune
|
go build -buildmode=pie -o external.exe rsc.io/fortune
|
||||||
|
|
|
||||||
140
src/cmd/go/testdata/script/work.txt
vendored
Normal file
140
src/cmd/go/testdata/script/work.txt
vendored
Normal file
|
|
@ -0,0 +1,140 @@
|
||||||
|
go mod initwork ./a ./b
|
||||||
|
cmp go.work go.work.want
|
||||||
|
|
||||||
|
! go run example.com/b
|
||||||
|
stderr 'a(\\|/)a.go:4:8: no required module provides package rsc.io/quote; to add it:\n\tcd '$WORK(\\|/)gopath(\\|/)src(\\|/)a'\n\tgo get rsc.io/quote'
|
||||||
|
cd a
|
||||||
|
go get rsc.io/quote
|
||||||
|
go env GOMOD # go env GOMOD reports the module in a single module context
|
||||||
|
stdout $GOPATH(\\|/)src(\\|/)a(\\|/)go.mod
|
||||||
|
cd ..
|
||||||
|
go run example.com/b
|
||||||
|
stdout 'Hello, world.'
|
||||||
|
|
||||||
|
# And try from a different directory
|
||||||
|
cd c
|
||||||
|
go run example.com/b
|
||||||
|
stdout 'Hello, world.'
|
||||||
|
cd $GOPATH/src
|
||||||
|
|
||||||
|
go list all # all includes both modules
|
||||||
|
stdout 'example.com/a'
|
||||||
|
stdout 'example.com/b'
|
||||||
|
|
||||||
|
# -mod can only be set to readonly in workspace mode
|
||||||
|
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
|
||||||
|
|
||||||
|
# Test that duplicates in the directory list return an error
|
||||||
|
cp go.work go.work.backup
|
||||||
|
cp go.work.dup go.work
|
||||||
|
! go run example.com/b
|
||||||
|
stderr 'reading go.work: path .* appears multiple times in workspace'
|
||||||
|
cp go.work.backup go.work
|
||||||
|
|
||||||
|
cp go.work.d go.work
|
||||||
|
go run example.com/d
|
||||||
|
|
||||||
|
# Test that we don't run into "newRequirements called with unsorted roots"
|
||||||
|
# panic with unsorted main modules.
|
||||||
|
cp go.work.backwards go.work
|
||||||
|
go run example.com/d
|
||||||
|
|
||||||
|
# Test that command-line-arguments work inside and outside modules.
|
||||||
|
# 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
|
||||||
|
go build -n -o foo foo.go
|
||||||
|
|
||||||
|
-- go.work.dup --
|
||||||
|
go 1.18
|
||||||
|
|
||||||
|
directory (
|
||||||
|
a
|
||||||
|
b
|
||||||
|
../src/a
|
||||||
|
)
|
||||||
|
-- go.work.want --
|
||||||
|
go 1.18
|
||||||
|
|
||||||
|
directory (
|
||||||
|
./a
|
||||||
|
./b
|
||||||
|
)
|
||||||
|
-- go.work.d --
|
||||||
|
go 1.18
|
||||||
|
|
||||||
|
directory (
|
||||||
|
a
|
||||||
|
b
|
||||||
|
d
|
||||||
|
)
|
||||||
|
-- a/go.mod --
|
||||||
|
|
||||||
|
module example.com/a
|
||||||
|
|
||||||
|
-- a/a.go --
|
||||||
|
package a
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
import "rsc.io/quote"
|
||||||
|
|
||||||
|
func HelloFromA() {
|
||||||
|
fmt.Println(quote.Hello())
|
||||||
|
}
|
||||||
|
|
||||||
|
-- b/go.mod --
|
||||||
|
|
||||||
|
module example.com/b
|
||||||
|
|
||||||
|
-- b/main.go --
|
||||||
|
package main
|
||||||
|
|
||||||
|
import "example.com/a"
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
a.HelloFromA()
|
||||||
|
}
|
||||||
|
-- b/lib/hello.go --
|
||||||
|
package lib
|
||||||
|
|
||||||
|
import "example.com/a"
|
||||||
|
|
||||||
|
func Hello() {
|
||||||
|
a.HelloFromA()
|
||||||
|
}
|
||||||
|
|
||||||
|
-- c/README --
|
||||||
|
Create this directory so we can cd to
|
||||||
|
it and make sure paths are interpreted
|
||||||
|
relative to the go.work, not the cwd.
|
||||||
|
-- d/go.mod --
|
||||||
|
module example.com/d
|
||||||
|
|
||||||
|
-- d/main.go --
|
||||||
|
package main
|
||||||
|
|
||||||
|
import "example.com/b/lib"
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
lib.Hello()
|
||||||
|
}
|
||||||
|
|
||||||
|
-- go.work.backwards --
|
||||||
|
go 1.18
|
||||||
|
|
||||||
|
directory (
|
||||||
|
d
|
||||||
|
b
|
||||||
|
a
|
||||||
|
)
|
||||||
|
|
||||||
|
-- foo.go --
|
||||||
|
package main
|
||||||
|
import "fmt"
|
||||||
|
func main() {
|
||||||
|
fmt.Println("Hello, World")
|
||||||
|
}
|
||||||
157
src/cmd/go/testdata/script/work_edit.txt
vendored
Normal file
157
src/cmd/go/testdata/script/work_edit.txt
vendored
Normal file
|
|
@ -0,0 +1,157 @@
|
||||||
|
# Test editing go.work files.
|
||||||
|
|
||||||
|
go mod initwork m
|
||||||
|
cmp go.work go.work.want_initial
|
||||||
|
|
||||||
|
go mod editwork -directory n
|
||||||
|
cmp go.work go.work.want_directory_n
|
||||||
|
|
||||||
|
go mod editwork -go 1.18
|
||||||
|
cmp go.work go.work.want_go_118
|
||||||
|
|
||||||
|
go mod editwork -dropdirectory m
|
||||||
|
cmp go.work go.work.want_dropdirectory_m
|
||||||
|
|
||||||
|
go mod editwork -replace=x.1@v1.3.0=y.1@v1.4.0 -replace='x.1@v1.4.0 = ../z'
|
||||||
|
cmp go.work go.work.want_add_replaces
|
||||||
|
|
||||||
|
go mod editwork -directory n -directory ../a -directory /b -directory c -directory c
|
||||||
|
cmp go.work go.work.want_multidirectory
|
||||||
|
|
||||||
|
go mod editwork -dropdirectory /b -dropdirectory n
|
||||||
|
cmp go.work go.work.want_multidropdirectory
|
||||||
|
|
||||||
|
go mod editwork -dropreplace='x.1@v1.4.0'
|
||||||
|
cmp go.work go.work.want_dropreplace
|
||||||
|
|
||||||
|
go mod editwork -print -go 1.19 -directory b -dropdirectory c -replace 'x.1@v1.4.0 = ../z' -dropreplace x.1 -dropreplace x.1@v1.3.0
|
||||||
|
cmp stdout go.work.want_print
|
||||||
|
|
||||||
|
go mod editwork -json -go 1.19 -directory b -dropdirectory c -replace 'x.1@v1.4.0 = ../z' -dropreplace x.1 -dropreplace x.1@v1.3.0
|
||||||
|
cmp stdout go.work.want_json
|
||||||
|
|
||||||
|
go mod editwork -print -fmt -workfile unformatted
|
||||||
|
cmp stdout formatted
|
||||||
|
|
||||||
|
-- go.work.want_initial --
|
||||||
|
go 1.18
|
||||||
|
|
||||||
|
directory m
|
||||||
|
-- go.work.want_directory_n --
|
||||||
|
go 1.18
|
||||||
|
|
||||||
|
directory (
|
||||||
|
m
|
||||||
|
n
|
||||||
|
)
|
||||||
|
-- go.work.want_go_118 --
|
||||||
|
go 1.18
|
||||||
|
|
||||||
|
directory (
|
||||||
|
m
|
||||||
|
n
|
||||||
|
)
|
||||||
|
-- go.work.want_dropdirectory_m --
|
||||||
|
go 1.18
|
||||||
|
|
||||||
|
directory n
|
||||||
|
-- go.work.want_add_replaces --
|
||||||
|
go 1.18
|
||||||
|
|
||||||
|
directory n
|
||||||
|
|
||||||
|
replace (
|
||||||
|
x.1 v1.3.0 => y.1 v1.4.0
|
||||||
|
x.1 v1.4.0 => ../z
|
||||||
|
)
|
||||||
|
-- go.work.want_multidirectory --
|
||||||
|
go 1.18
|
||||||
|
|
||||||
|
directory (
|
||||||
|
../a
|
||||||
|
/b
|
||||||
|
c
|
||||||
|
n
|
||||||
|
)
|
||||||
|
|
||||||
|
replace (
|
||||||
|
x.1 v1.3.0 => y.1 v1.4.0
|
||||||
|
x.1 v1.4.0 => ../z
|
||||||
|
)
|
||||||
|
-- go.work.want_multidropdirectory --
|
||||||
|
go 1.18
|
||||||
|
|
||||||
|
directory (
|
||||||
|
../a
|
||||||
|
c
|
||||||
|
)
|
||||||
|
|
||||||
|
replace (
|
||||||
|
x.1 v1.3.0 => y.1 v1.4.0
|
||||||
|
x.1 v1.4.0 => ../z
|
||||||
|
)
|
||||||
|
-- go.work.want_dropreplace --
|
||||||
|
go 1.18
|
||||||
|
|
||||||
|
directory (
|
||||||
|
../a
|
||||||
|
c
|
||||||
|
)
|
||||||
|
|
||||||
|
replace x.1 v1.3.0 => y.1 v1.4.0
|
||||||
|
-- go.work.want_print --
|
||||||
|
go 1.19
|
||||||
|
|
||||||
|
directory (
|
||||||
|
../a
|
||||||
|
b
|
||||||
|
)
|
||||||
|
|
||||||
|
replace x.1 v1.4.0 => ../z
|
||||||
|
-- go.work.want_json --
|
||||||
|
{
|
||||||
|
"Go": "1.19",
|
||||||
|
"Directory": [
|
||||||
|
{
|
||||||
|
"DiskPath": "../a"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"DiskPath": "b"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"Replace": [
|
||||||
|
{
|
||||||
|
"Old": {
|
||||||
|
"Path": "x.1",
|
||||||
|
"Version": "v1.4.0"
|
||||||
|
},
|
||||||
|
"New": {
|
||||||
|
"Path": "../z"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
-- unformatted --
|
||||||
|
go 1.18
|
||||||
|
directory (
|
||||||
|
a
|
||||||
|
b
|
||||||
|
c
|
||||||
|
)
|
||||||
|
replace (
|
||||||
|
x.1 v1.3.0 => y.1 v1.4.0
|
||||||
|
x.1 v1.4.0 => ../z
|
||||||
|
)
|
||||||
|
-- formatted --
|
||||||
|
go 1.18
|
||||||
|
|
||||||
|
directory (
|
||||||
|
a
|
||||||
|
b
|
||||||
|
c
|
||||||
|
)
|
||||||
|
|
||||||
|
replace (
|
||||||
|
x.1 v1.3.0 => y.1 v1.4.0
|
||||||
|
x.1 v1.4.0 => ../z
|
||||||
|
)
|
||||||
33
src/cmd/go/testdata/script/work_sum.txt
vendored
Normal file
33
src/cmd/go/testdata/script/work_sum.txt
vendored
Normal file
|
|
@ -0,0 +1,33 @@
|
||||||
|
# Test adding sums to go.work.sum when sum isn't in go.mod.
|
||||||
|
|
||||||
|
go run .
|
||||||
|
cmp go.work.sum want.sum
|
||||||
|
|
||||||
|
-- want.sum --
|
||||||
|
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c h1:pvCbr/wm8HzDD3fVywevekufpn6tCGPY3spdHeZJEsw=
|
||||||
|
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
|
rsc.io/quote v1.5.2 h1:3fEykkD9k7lYzXqCYrwGAf7iNhbk4yCjHmKBN9td4L0=
|
||||||
|
rsc.io/quote v1.5.2/go.mod h1:LzX7hefJvL54yjefDEDHNONDjII0t9xZLPXsUe+TKr0=
|
||||||
|
rsc.io/sampler v1.3.0 h1:HLGR/BgEtI3r0uymSP/nl2uPLsUnNJX8toRyhfpBTII=
|
||||||
|
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
|
||||||
|
-- go.work --
|
||||||
|
go 1.18
|
||||||
|
|
||||||
|
directory .
|
||||||
|
-- go.mod --
|
||||||
|
go 1.18
|
||||||
|
|
||||||
|
module example.com/hi
|
||||||
|
|
||||||
|
require "rsc.io/quote" v1.5.2
|
||||||
|
-- main.go --
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"rsc.io/quote"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
fmt.Println(quote.Hello())
|
||||||
|
}
|
||||||
250
src/cmd/vendor/golang.org/x/mod/modfile/rule.go
generated
vendored
250
src/cmd/vendor/golang.org/x/mod/modfile/rule.go
generated
vendored
|
|
@ -423,68 +423,12 @@ func (f *File) add(errs *ErrorList, block *LineBlock, line *Line, verb string, a
|
||||||
}
|
}
|
||||||
|
|
||||||
case "replace":
|
case "replace":
|
||||||
arrow := 2
|
replace, wrappederr := parseReplace(f.Syntax.Name, line, verb, args, fix)
|
||||||
if len(args) >= 2 && args[1] == "=>" {
|
if wrappederr != nil {
|
||||||
arrow = 1
|
*errs = append(*errs, *wrappederr)
|
||||||
}
|
|
||||||
if len(args) < arrow+2 || len(args) > arrow+3 || args[arrow] != "=>" {
|
|
||||||
errorf("usage: %s module/path [v1.2.3] => other/module v1.4\n\t or %s module/path [v1.2.3] => ../local/directory", verb, verb)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
s, err := parseString(&args[0])
|
f.Replace = append(f.Replace, replace)
|
||||||
if err != nil {
|
|
||||||
errorf("invalid quoted string: %v", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
pathMajor, err := modulePathMajor(s)
|
|
||||||
if err != nil {
|
|
||||||
wrapModPathError(s, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
var v string
|
|
||||||
if arrow == 2 {
|
|
||||||
v, err = parseVersion(verb, s, &args[1], fix)
|
|
||||||
if err != nil {
|
|
||||||
wrapError(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if err := module.CheckPathMajor(v, pathMajor); err != nil {
|
|
||||||
wrapModPathError(s, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ns, err := parseString(&args[arrow+1])
|
|
||||||
if err != nil {
|
|
||||||
errorf("invalid quoted string: %v", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
nv := ""
|
|
||||||
if len(args) == arrow+2 {
|
|
||||||
if !IsDirectoryPath(ns) {
|
|
||||||
errorf("replacement module without version must be directory path (rooted or starting with ./ or ../)")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if filepath.Separator == '/' && strings.Contains(ns, `\`) {
|
|
||||||
errorf("replacement directory appears to be Windows path (on a non-windows system)")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if len(args) == arrow+3 {
|
|
||||||
nv, err = parseVersion(verb, ns, &args[arrow+2], fix)
|
|
||||||
if err != nil {
|
|
||||||
wrapError(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if IsDirectoryPath(ns) {
|
|
||||||
errorf("replacement module directory path %q cannot have version", ns)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
f.Replace = append(f.Replace, &Replace{
|
|
||||||
Old: module.Version{Path: s, Version: v},
|
|
||||||
New: module.Version{Path: ns, Version: nv},
|
|
||||||
Syntax: line,
|
|
||||||
})
|
|
||||||
|
|
||||||
case "retract":
|
case "retract":
|
||||||
rationale := parseDirectiveComment(block, line)
|
rationale := parseDirectiveComment(block, line)
|
||||||
|
|
@ -515,6 +459,83 @@ func (f *File) add(errs *ErrorList, block *LineBlock, line *Line, verb string, a
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func parseReplace(filename string, line *Line, verb string, args []string, fix VersionFixer) (*Replace, *Error) {
|
||||||
|
wrapModPathError := func(modPath string, err error) *Error {
|
||||||
|
return &Error{
|
||||||
|
Filename: filename,
|
||||||
|
Pos: line.Start,
|
||||||
|
ModPath: modPath,
|
||||||
|
Verb: verb,
|
||||||
|
Err: err,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
wrapError := func(err error) *Error {
|
||||||
|
return &Error{
|
||||||
|
Filename: filename,
|
||||||
|
Pos: line.Start,
|
||||||
|
Err: err,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
errorf := func(format string, args ...interface{}) *Error {
|
||||||
|
return wrapError(fmt.Errorf(format, args...))
|
||||||
|
}
|
||||||
|
|
||||||
|
arrow := 2
|
||||||
|
if len(args) >= 2 && args[1] == "=>" {
|
||||||
|
arrow = 1
|
||||||
|
}
|
||||||
|
if len(args) < arrow+2 || len(args) > arrow+3 || args[arrow] != "=>" {
|
||||||
|
return nil, errorf("usage: %s module/path [v1.2.3] => other/module v1.4\n\t or %s module/path [v1.2.3] => ../local/directory", verb, verb)
|
||||||
|
}
|
||||||
|
s, err := parseString(&args[0])
|
||||||
|
if err != nil {
|
||||||
|
return nil, errorf("invalid quoted string: %v", err)
|
||||||
|
}
|
||||||
|
pathMajor, err := modulePathMajor(s)
|
||||||
|
if err != nil {
|
||||||
|
return nil, wrapModPathError(s, err)
|
||||||
|
|
||||||
|
}
|
||||||
|
var v string
|
||||||
|
if arrow == 2 {
|
||||||
|
v, err = parseVersion(verb, s, &args[1], fix)
|
||||||
|
if err != nil {
|
||||||
|
return nil, wrapError(err)
|
||||||
|
}
|
||||||
|
if err := module.CheckPathMajor(v, pathMajor); err != nil {
|
||||||
|
return nil, wrapModPathError(s, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ns, err := parseString(&args[arrow+1])
|
||||||
|
if err != nil {
|
||||||
|
return nil, errorf("invalid quoted string: %v", err)
|
||||||
|
}
|
||||||
|
nv := ""
|
||||||
|
if len(args) == arrow+2 {
|
||||||
|
if !IsDirectoryPath(ns) {
|
||||||
|
return nil, errorf("replacement module without version must be directory path (rooted or starting with ./ or ../)")
|
||||||
|
}
|
||||||
|
if filepath.Separator == '/' && strings.Contains(ns, `\`) {
|
||||||
|
return nil, errorf("replacement directory appears to be Windows path (on a non-windows system)")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(args) == arrow+3 {
|
||||||
|
nv, err = parseVersion(verb, ns, &args[arrow+2], fix)
|
||||||
|
if err != nil {
|
||||||
|
return nil, wrapError(err)
|
||||||
|
}
|
||||||
|
if IsDirectoryPath(ns) {
|
||||||
|
return nil, errorf("replacement module directory path %q cannot have version", ns)
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return &Replace{
|
||||||
|
Old: module.Version{Path: s, Version: v},
|
||||||
|
New: module.Version{Path: ns, Version: nv},
|
||||||
|
Syntax: line,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
// fixRetract applies fix to each retract directive in f, appending any errors
|
// fixRetract applies fix to each retract directive in f, appending any errors
|
||||||
// to errs.
|
// to errs.
|
||||||
//
|
//
|
||||||
|
|
@ -556,6 +577,63 @@ func (f *File) fixRetract(fix VersionFixer, errs *ErrorList) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (f *WorkFile) add(errs *ErrorList, line *Line, verb string, args []string, fix VersionFixer) {
|
||||||
|
wrapError := func(err error) {
|
||||||
|
*errs = append(*errs, Error{
|
||||||
|
Filename: f.Syntax.Name,
|
||||||
|
Pos: line.Start,
|
||||||
|
Err: err,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
errorf := func(format string, args ...interface{}) {
|
||||||
|
wrapError(fmt.Errorf(format, args...))
|
||||||
|
}
|
||||||
|
|
||||||
|
switch verb {
|
||||||
|
default:
|
||||||
|
errorf("unknown directive: %s", verb)
|
||||||
|
|
||||||
|
case "go":
|
||||||
|
if f.Go != nil {
|
||||||
|
errorf("repeated go statement")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if len(args) != 1 {
|
||||||
|
errorf("go directive expects exactly one argument")
|
||||||
|
return
|
||||||
|
} else if !GoVersionRE.MatchString(args[0]) {
|
||||||
|
errorf("invalid go version '%s': must match format 1.23", args[0])
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
f.Go = &Go{Syntax: line}
|
||||||
|
f.Go.Version = args[0]
|
||||||
|
|
||||||
|
case "directory":
|
||||||
|
if len(args) != 1 {
|
||||||
|
errorf("usage: %s local/dir", verb)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
s, err := parseString(&args[0])
|
||||||
|
if err != nil {
|
||||||
|
errorf("invalid quoted string: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
f.Directory = append(f.Directory, &Directory{
|
||||||
|
Path: s,
|
||||||
|
Syntax: line,
|
||||||
|
})
|
||||||
|
|
||||||
|
case "replace":
|
||||||
|
replace, wrappederr := parseReplace(f.Syntax.Name, line, verb, args, fix)
|
||||||
|
if wrappederr != nil {
|
||||||
|
*errs = append(*errs, *wrappederr)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
f.Replace = append(f.Replace, replace)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// IsDirectoryPath reports whether the given path should be interpreted
|
// IsDirectoryPath reports whether the given path should be interpreted
|
||||||
// as a directory path. Just like on the go command line, relative paths
|
// as a directory path. Just like on the go command line, relative paths
|
||||||
// and rooted paths are directory paths; the rest are module paths.
|
// and rooted paths are directory paths; the rest are module paths.
|
||||||
|
|
@ -1165,6 +1243,10 @@ func (f *File) DropExclude(path, vers string) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *File) AddReplace(oldPath, oldVers, newPath, newVers string) error {
|
func (f *File) AddReplace(oldPath, oldVers, newPath, newVers string) error {
|
||||||
|
return addReplace(f.Syntax, &f.Replace, oldPath, oldVers, newPath, newVers)
|
||||||
|
}
|
||||||
|
|
||||||
|
func addReplace(syntax *FileSyntax, replace *[]*Replace, oldPath, oldVers, newPath, newVers string) error {
|
||||||
need := true
|
need := true
|
||||||
old := module.Version{Path: oldPath, Version: oldVers}
|
old := module.Version{Path: oldPath, Version: oldVers}
|
||||||
new := module.Version{Path: newPath, Version: newVers}
|
new := module.Version{Path: newPath, Version: newVers}
|
||||||
|
|
@ -1178,12 +1260,12 @@ func (f *File) AddReplace(oldPath, oldVers, newPath, newVers string) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
var hint *Line
|
var hint *Line
|
||||||
for _, r := range f.Replace {
|
for _, r := range *replace {
|
||||||
if r.Old.Path == oldPath && (oldVers == "" || r.Old.Version == oldVers) {
|
if r.Old.Path == oldPath && (oldVers == "" || r.Old.Version == oldVers) {
|
||||||
if need {
|
if need {
|
||||||
// Found replacement for old; update to use new.
|
// Found replacement for old; update to use new.
|
||||||
r.New = new
|
r.New = new
|
||||||
f.Syntax.updateLine(r.Syntax, tokens...)
|
syntax.updateLine(r.Syntax, tokens...)
|
||||||
need = false
|
need = false
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
@ -1196,7 +1278,7 @@ func (f *File) AddReplace(oldPath, oldVers, newPath, newVers string) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if need {
|
if need {
|
||||||
f.Replace = append(f.Replace, &Replace{Old: old, New: new, Syntax: f.Syntax.addLine(hint, tokens...)})
|
*replace = append(*replace, &Replace{Old: old, New: new, Syntax: syntax.addLine(hint, tokens...)})
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
@ -1282,30 +1364,36 @@ func (f *File) SortBlocks() {
|
||||||
// retract directives are not de-duplicated since comments are
|
// retract directives are not de-duplicated since comments are
|
||||||
// meaningful, and versions may be retracted multiple times.
|
// meaningful, and versions may be retracted multiple times.
|
||||||
func (f *File) removeDups() {
|
func (f *File) removeDups() {
|
||||||
|
removeDups(f.Syntax, &f.Exclude, &f.Replace)
|
||||||
|
}
|
||||||
|
|
||||||
|
func removeDups(syntax *FileSyntax, exclude *[]*Exclude, replace *[]*Replace) {
|
||||||
kill := make(map[*Line]bool)
|
kill := make(map[*Line]bool)
|
||||||
|
|
||||||
// Remove duplicate excludes.
|
// Remove duplicate excludes.
|
||||||
haveExclude := make(map[module.Version]bool)
|
if exclude != nil {
|
||||||
for _, x := range f.Exclude {
|
haveExclude := make(map[module.Version]bool)
|
||||||
if haveExclude[x.Mod] {
|
for _, x := range *exclude {
|
||||||
kill[x.Syntax] = true
|
if haveExclude[x.Mod] {
|
||||||
continue
|
kill[x.Syntax] = true
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
haveExclude[x.Mod] = true
|
||||||
}
|
}
|
||||||
haveExclude[x.Mod] = true
|
var excl []*Exclude
|
||||||
}
|
for _, x := range *exclude {
|
||||||
var excl []*Exclude
|
if !kill[x.Syntax] {
|
||||||
for _, x := range f.Exclude {
|
excl = append(excl, x)
|
||||||
if !kill[x.Syntax] {
|
}
|
||||||
excl = append(excl, x)
|
|
||||||
}
|
}
|
||||||
|
*exclude = excl
|
||||||
}
|
}
|
||||||
f.Exclude = excl
|
|
||||||
|
|
||||||
// Remove duplicate replacements.
|
// Remove duplicate replacements.
|
||||||
// Later replacements take priority over earlier ones.
|
// Later replacements take priority over earlier ones.
|
||||||
haveReplace := make(map[module.Version]bool)
|
haveReplace := make(map[module.Version]bool)
|
||||||
for i := len(f.Replace) - 1; i >= 0; i-- {
|
for i := len(*replace) - 1; i >= 0; i-- {
|
||||||
x := f.Replace[i]
|
x := (*replace)[i]
|
||||||
if haveReplace[x.Old] {
|
if haveReplace[x.Old] {
|
||||||
kill[x.Syntax] = true
|
kill[x.Syntax] = true
|
||||||
continue
|
continue
|
||||||
|
|
@ -1313,18 +1401,18 @@ func (f *File) removeDups() {
|
||||||
haveReplace[x.Old] = true
|
haveReplace[x.Old] = true
|
||||||
}
|
}
|
||||||
var repl []*Replace
|
var repl []*Replace
|
||||||
for _, x := range f.Replace {
|
for _, x := range *replace {
|
||||||
if !kill[x.Syntax] {
|
if !kill[x.Syntax] {
|
||||||
repl = append(repl, x)
|
repl = append(repl, x)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
f.Replace = repl
|
*replace = repl
|
||||||
|
|
||||||
// Duplicate require and retract directives are not removed.
|
// Duplicate require and retract directives are not removed.
|
||||||
|
|
||||||
// Drop killed statements from the syntax tree.
|
// Drop killed statements from the syntax tree.
|
||||||
var stmts []Expr
|
var stmts []Expr
|
||||||
for _, stmt := range f.Syntax.Stmt {
|
for _, stmt := range syntax.Stmt {
|
||||||
switch stmt := stmt.(type) {
|
switch stmt := stmt.(type) {
|
||||||
case *Line:
|
case *Line:
|
||||||
if kill[stmt] {
|
if kill[stmt] {
|
||||||
|
|
@ -1344,7 +1432,7 @@ func (f *File) removeDups() {
|
||||||
}
|
}
|
||||||
stmts = append(stmts, stmt)
|
stmts = append(stmts, stmt)
|
||||||
}
|
}
|
||||||
f.Syntax.Stmt = stmts
|
syntax.Stmt = stmts
|
||||||
}
|
}
|
||||||
|
|
||||||
// lineLess returns whether li should be sorted before lj. It sorts
|
// lineLess returns whether li should be sorted before lj. It sorts
|
||||||
|
|
|
||||||
234
src/cmd/vendor/golang.org/x/mod/modfile/work.go
generated
vendored
Normal file
234
src/cmd/vendor/golang.org/x/mod/modfile/work.go
generated
vendored
Normal file
|
|
@ -0,0 +1,234 @@
|
||||||
|
// Copyright 2021 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package modfile
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"sort"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// A WorkFile is the parsed, interpreted form of a go.work file.
|
||||||
|
type WorkFile struct {
|
||||||
|
Go *Go
|
||||||
|
Directory []*Directory
|
||||||
|
Replace []*Replace
|
||||||
|
|
||||||
|
Syntax *FileSyntax
|
||||||
|
}
|
||||||
|
|
||||||
|
// A Directory is a single directory statement.
|
||||||
|
type Directory struct {
|
||||||
|
Path string // Directory path of module.
|
||||||
|
ModulePath string // Module path in the comment.
|
||||||
|
Syntax *Line
|
||||||
|
}
|
||||||
|
|
||||||
|
// ParseWork parses and returns a go.work file.
|
||||||
|
//
|
||||||
|
// file is the name of the file, used in positions and errors.
|
||||||
|
//
|
||||||
|
// data is the content of the file.
|
||||||
|
//
|
||||||
|
// fix is an optional function that canonicalizes module versions.
|
||||||
|
// If fix is nil, all module versions must be canonical (module.CanonicalVersion
|
||||||
|
// must return the same string).
|
||||||
|
func ParseWork(file string, data []byte, fix VersionFixer) (*WorkFile, error) {
|
||||||
|
fs, err := parse(file, data)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
f := &WorkFile{
|
||||||
|
Syntax: fs,
|
||||||
|
}
|
||||||
|
var errs ErrorList
|
||||||
|
|
||||||
|
for _, x := range fs.Stmt {
|
||||||
|
switch x := x.(type) {
|
||||||
|
case *Line:
|
||||||
|
f.add(&errs, x, x.Token[0], x.Token[1:], fix)
|
||||||
|
|
||||||
|
case *LineBlock:
|
||||||
|
if len(x.Token) > 1 {
|
||||||
|
errs = append(errs, Error{
|
||||||
|
Filename: file,
|
||||||
|
Pos: x.Start,
|
||||||
|
Err: fmt.Errorf("unknown block type: %s", strings.Join(x.Token, " ")),
|
||||||
|
})
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
switch x.Token[0] {
|
||||||
|
default:
|
||||||
|
errs = append(errs, Error{
|
||||||
|
Filename: file,
|
||||||
|
Pos: x.Start,
|
||||||
|
Err: fmt.Errorf("unknown block type: %s", strings.Join(x.Token, " ")),
|
||||||
|
})
|
||||||
|
continue
|
||||||
|
case "directory", "replace":
|
||||||
|
for _, l := range x.Line {
|
||||||
|
f.add(&errs, l, x.Token[0], l.Token, fix)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(errs) > 0 {
|
||||||
|
return nil, errs
|
||||||
|
}
|
||||||
|
return f, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cleanup cleans up the file f after any edit operations.
|
||||||
|
// To avoid quadratic behavior, modifications like DropRequire
|
||||||
|
// clear the entry but do not remove it from the slice.
|
||||||
|
// Cleanup cleans out all the cleared entries.
|
||||||
|
func (f *WorkFile) Cleanup() {
|
||||||
|
w := 0
|
||||||
|
for _, r := range f.Directory {
|
||||||
|
if r.Path != "" {
|
||||||
|
f.Directory[w] = r
|
||||||
|
w++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
f.Directory = f.Directory[:w]
|
||||||
|
|
||||||
|
w = 0
|
||||||
|
for _, r := range f.Replace {
|
||||||
|
if r.Old.Path != "" {
|
||||||
|
f.Replace[w] = r
|
||||||
|
w++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
f.Replace = f.Replace[:w]
|
||||||
|
|
||||||
|
f.Syntax.Cleanup()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *WorkFile) AddGoStmt(version string) error {
|
||||||
|
if !GoVersionRE.MatchString(version) {
|
||||||
|
return fmt.Errorf("invalid language version string %q", version)
|
||||||
|
}
|
||||||
|
if f.Go == nil {
|
||||||
|
stmt := &Line{Token: []string{"go", version}}
|
||||||
|
f.Go = &Go{
|
||||||
|
Version: version,
|
||||||
|
Syntax: stmt,
|
||||||
|
}
|
||||||
|
// Find the first non-comment-only block that's and add
|
||||||
|
// the go statement before it. That will keep file comments at the top.
|
||||||
|
i := 0
|
||||||
|
for i = 0; i < len(f.Syntax.Stmt); i++ {
|
||||||
|
if _, ok := f.Syntax.Stmt[i].(*CommentBlock); !ok {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
f.Syntax.Stmt = append(append(f.Syntax.Stmt[:i:i], stmt), f.Syntax.Stmt[i:]...)
|
||||||
|
} else {
|
||||||
|
f.Go.Version = version
|
||||||
|
f.Syntax.updateLine(f.Go.Syntax, "go", version)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *WorkFile) AddDirectory(diskPath, modulePath string) error {
|
||||||
|
need := true
|
||||||
|
for _, d := range f.Directory {
|
||||||
|
if d.Path == diskPath {
|
||||||
|
if need {
|
||||||
|
d.ModulePath = modulePath
|
||||||
|
f.Syntax.updateLine(d.Syntax, "directory", AutoQuote(diskPath))
|
||||||
|
need = false
|
||||||
|
} else {
|
||||||
|
d.Syntax.markRemoved()
|
||||||
|
*d = Directory{}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if need {
|
||||||
|
f.AddNewDirectory(diskPath, modulePath)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *WorkFile) AddNewDirectory(diskPath, modulePath string) {
|
||||||
|
line := f.Syntax.addLine(nil, "directory", AutoQuote(diskPath))
|
||||||
|
f.Directory = append(f.Directory, &Directory{Path: diskPath, ModulePath: modulePath, Syntax: line})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *WorkFile) SetDirectory(dirs []*Directory) {
|
||||||
|
need := make(map[string]string)
|
||||||
|
for _, d := range dirs {
|
||||||
|
need[d.Path] = d.ModulePath
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, d := range f.Directory {
|
||||||
|
if modulePath, ok := need[d.Path]; ok {
|
||||||
|
d.ModulePath = modulePath
|
||||||
|
} else {
|
||||||
|
d.Syntax.markRemoved()
|
||||||
|
*d = Directory{}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO(#45713): Add module path to comment.
|
||||||
|
|
||||||
|
for diskPath, modulePath := range need {
|
||||||
|
f.AddNewDirectory(diskPath, modulePath)
|
||||||
|
}
|
||||||
|
f.SortBlocks()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *WorkFile) DropDirectory(path string) error {
|
||||||
|
for _, d := range f.Directory {
|
||||||
|
if d.Path == path {
|
||||||
|
d.Syntax.markRemoved()
|
||||||
|
*d = Directory{}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *WorkFile) AddReplace(oldPath, oldVers, newPath, newVers string) error {
|
||||||
|
return addReplace(f.Syntax, &f.Replace, oldPath, oldVers, newPath, newVers)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *WorkFile) DropReplace(oldPath, oldVers string) error {
|
||||||
|
for _, r := range f.Replace {
|
||||||
|
if r.Old.Path == oldPath && r.Old.Version == oldVers {
|
||||||
|
r.Syntax.markRemoved()
|
||||||
|
*r = Replace{}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *WorkFile) SortBlocks() {
|
||||||
|
f.removeDups() // otherwise sorting is unsafe
|
||||||
|
|
||||||
|
for _, stmt := range f.Syntax.Stmt {
|
||||||
|
block, ok := stmt.(*LineBlock)
|
||||||
|
if !ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
sort.SliceStable(block.Line, func(i, j int) bool {
|
||||||
|
return lineLess(block.Line[i], block.Line[j])
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// removeDups removes duplicate replace directives.
|
||||||
|
//
|
||||||
|
// Later replace directives take priority.
|
||||||
|
//
|
||||||
|
// require directives are not de-duplicated. That's left up to higher-level
|
||||||
|
// logic (MVS).
|
||||||
|
//
|
||||||
|
// retract directives are not de-duplicated since comments are
|
||||||
|
// meaningful, and versions may be retracted multiple times.
|
||||||
|
func (f *WorkFile) removeDups() {
|
||||||
|
removeDups(f.Syntax, nil, &f.Replace)
|
||||||
|
}
|
||||||
2
src/cmd/vendor/modules.txt
vendored
2
src/cmd/vendor/modules.txt
vendored
|
|
@ -28,7 +28,7 @@ golang.org/x/arch/x86/x86asm
|
||||||
## explicit; go 1.17
|
## explicit; go 1.17
|
||||||
golang.org/x/crypto/ed25519
|
golang.org/x/crypto/ed25519
|
||||||
golang.org/x/crypto/ed25519/internal/edwards25519
|
golang.org/x/crypto/ed25519/internal/edwards25519
|
||||||
# golang.org/x/mod v0.4.3-0.20210608190319-0f08993efd8a
|
# golang.org/x/mod v0.4.3-0.20210723200715-e41a6a4f3b61
|
||||||
## explicit; go 1.17
|
## explicit; go 1.17
|
||||||
golang.org/x/mod/internal/lazyregexp
|
golang.org/x/mod/internal/lazyregexp
|
||||||
golang.org/x/mod/modfile
|
golang.org/x/mod/modfile
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue