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
|
||||
golang.org/x/arch v0.0.0-20210502124803-cbf565b21d1e
|
||||
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/term v0.0.0-20210503060354-a79de5458b56
|
||||
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/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/mod v0.4.3-0.20210608190319-0f08993efd8a h1:e8qnjKz4EE6OjRki9wTadWSIogINvq10sMcuBRORxMY=
|
||||
golang.org/x/mod v0.4.3-0.20210608190319-0f08993efd8a/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
|
||||
golang.org/x/mod v0.4.3-0.20210723200715-e41a6a4f3b61 h1:gQY3CVezomIImcWCpxp6Mhj+fXCOZ+gD8/88326LVqw=
|
||||
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-20210511113859-b0526f3d8744 h1:yhBbb4IRs2HS9PPlAg6DMC6mUOKexJBNsLf4Z+6En1Q=
|
||||
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
|
||||
// alternate go.sum file is also used: its path is derived from the
|
||||
// -modfile flag by trimming the ".mod" extension and appending ".sum".
|
||||
// -workfile file
|
||||
// in module aware mode, use the given go.work file as a workspace file.
|
||||
// By default or when -workfile is "auto", the go command searches for a
|
||||
// file named go.work in the current directory and then containing directories
|
||||
// until one is found. If a valid go.work file is found, the modules
|
||||
// specified will collectively be used as the main modules. If -workfile
|
||||
// is "off", or a go.work file is not found in "auto" mode, workspace
|
||||
// mode is disabled.
|
||||
// -overlay file
|
||||
// read a JSON config file that provides an overlay for build operations.
|
||||
// The file is a JSON struct with a single field, named 'Replace', that
|
||||
|
|
@ -1024,8 +1032,10 @@
|
|||
//
|
||||
// download download modules to local cache
|
||||
// edit edit go.mod from tools or scripts
|
||||
// editwork edit go.work from tools or scripts
|
||||
// graph print module requirement graph
|
||||
// init initialize new module in current directory
|
||||
// initwork initialize workspace file
|
||||
// tidy add missing and remove unused modules
|
||||
// vendor make vendored copy of dependencies
|
||||
// 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'.
|
||||
//
|
||||
//
|
||||
// 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
|
||||
//
|
||||
// Usage:
|
||||
|
|
@ -1221,6 +1302,23 @@
|
|||
// 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
|
||||
//
|
||||
// Usage:
|
||||
|
|
|
|||
|
|
@ -62,6 +62,13 @@ func AddModFlag(flags *flag.FlagSet) {
|
|||
flags.Var(explicitStringFlag{value: &cfg.BuildMod, explicit: &cfg.BuildModExplicit}, "mod", "")
|
||||
}
|
||||
|
||||
// AddWorkfileFlag adds the workfile flag to the flag set. It enables workspace
|
||||
// mode for commands that support it by resetting the cfg.WorkFile variable
|
||||
// to "" (equivalent to auto) rather than off.
|
||||
func AddWorkfileFlag(flags *flag.FlagSet) {
|
||||
flags.Var(explicitStringFlag{value: &cfg.WorkFile, explicit: &cfg.WorkFileExplicit}, "workfile", "")
|
||||
}
|
||||
|
||||
// AddModCommonFlags adds the module-related flags common to build commands
|
||||
// and 'go mod' subcommands.
|
||||
func AddModCommonFlags(flags *flag.FlagSet) {
|
||||
|
|
|
|||
|
|
@ -47,8 +47,10 @@ var (
|
|||
BuildWork bool // -work flag
|
||||
BuildX bool // -x flag
|
||||
|
||||
ModCacheRW bool // -modcacherw flag
|
||||
ModFile string // -modfile flag
|
||||
ModCacheRW bool // -modcacherw flag
|
||||
ModFile string // -modfile flag
|
||||
WorkFile string // -workfile flag
|
||||
WorkFileExplicit bool // whether -workfile was set explicitly
|
||||
|
||||
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.
|
||||
func ExtraEnvVars() []cfg.EnvVar {
|
||||
gomod := ""
|
||||
modload.Init()
|
||||
if modload.HasModRoot() {
|
||||
gomod = filepath.Join(modload.ModRoot(), "go.mod")
|
||||
gomod = modload.ModFilePath()
|
||||
} else if modload.Enabled() {
|
||||
gomod = os.DevNull
|
||||
}
|
||||
|
|
|
|||
|
|
@ -225,7 +225,8 @@ func downloadPaths(patterns []string) []string {
|
|||
base.ExitIfErrors()
|
||||
|
||||
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(), "...") {
|
||||
pkgs = append(pkgs, m.Pattern())
|
||||
} else {
|
||||
|
|
@ -315,7 +316,8 @@ func download(arg string, parent *load.Package, stk *load.ImportStack, mode int)
|
|||
if wildcardOkay && strings.Contains(arg, "...") {
|
||||
match := search.NewMatch(arg)
|
||||
if match.IsLocal() {
|
||||
match.MatchDirs()
|
||||
noModRoots := []string{} // We're in gopath mode, so there are no modroots.
|
||||
match.MatchDirs(noModRoots)
|
||||
args = match.Dirs
|
||||
} else {
|
||||
match.MatchPackages()
|
||||
|
|
|
|||
|
|
@ -316,6 +316,7 @@ For more about modules, see https://golang.org/ref/mod.
|
|||
func init() {
|
||||
CmdList.Run = runList // break init cycle
|
||||
work.AddBuildFlags(CmdList, work.DefaultBuildFlags)
|
||||
base.AddWorkfileFlag(&CmdList.Flag)
|
||||
}
|
||||
|
||||
var (
|
||||
|
|
@ -336,6 +337,8 @@ var (
|
|||
var nl = []byte{'\n'}
|
||||
|
||||
func runList(ctx context.Context, cmd *base.Command, args []string) {
|
||||
modload.InitWorkfile()
|
||||
|
||||
if *listFmt != "" && *listJson == true {
|
||||
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.
|
||||
// Pretend that the import path is the import path of the
|
||||
// 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.
|
||||
importerPath = modload.DirImportPath(ctx, importer.Dir)
|
||||
importerPath, _ = modload.MainModules.DirImportPath(ctx, importer.Dir)
|
||||
}
|
||||
parentOfInternal := p.ImportPath[:i]
|
||||
if str.HasPathPrefix(importerPath, parentOfInternal) {
|
||||
|
|
@ -2447,7 +2447,8 @@ func PackagesAndErrors(ctx context.Context, opts PackageOpts, patterns []string)
|
|||
}
|
||||
matches, _ = modload.LoadPackages(ctx, modOpts, patterns...)
|
||||
} else {
|
||||
matches = search.ImportPaths(patterns)
|
||||
noModRoots := []string{}
|
||||
matches = search.ImportPaths(patterns, noModRoots)
|
||||
}
|
||||
|
||||
var (
|
||||
|
|
|
|||
|
|
@ -66,6 +66,7 @@ func init() {
|
|||
// TODO(jayconrod): https://golang.org/issue/35849 Apply -x to other 'go mod' commands.
|
||||
cmdDownload.Flag.BoolVar(&cfg.BuildX, "x", false, "")
|
||||
base.AddModCommonFlags(&cmdDownload.Flag)
|
||||
base.AddWorkfileFlag(&cmdDownload.Flag)
|
||||
}
|
||||
|
||||
type moduleJSON struct {
|
||||
|
|
@ -81,6 +82,8 @@ type moduleJSON struct {
|
|||
}
|
||||
|
||||
func runDownload(ctx context.Context, cmd *base.Command, args []string) {
|
||||
modload.InitWorkfile()
|
||||
|
||||
// Check whether modules are enabled and whether we're in a module.
|
||||
modload.ForceUseModules = true
|
||||
if !modload.HasModRoot() && len(args) == 0 {
|
||||
|
|
@ -91,12 +94,18 @@ func runDownload(ctx context.Context, cmd *base.Command, args []string) {
|
|||
args = []string{"all"}
|
||||
}
|
||||
if modload.HasModRoot() {
|
||||
modload.LoadModFile(ctx) // to fill Target
|
||||
targetAtUpgrade := modload.Target.Path + "@upgrade"
|
||||
targetAtPatch := modload.Target.Path + "@patch"
|
||||
modload.LoadModFile(ctx) // to fill MainModules
|
||||
|
||||
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 {
|
||||
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")
|
||||
}
|
||||
}
|
||||
|
|
|
|||
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() {
|
||||
cmdGraph.Flag.Var(&graphGo, "go", "")
|
||||
base.AddModCommonFlags(&cmdGraph.Flag)
|
||||
base.AddWorkfileFlag(&cmdGraph.Flag)
|
||||
}
|
||||
|
||||
func runGraph(ctx context.Context, cmd *base.Command, args []string) {
|
||||
modload.InitWorkfile()
|
||||
|
||||
if len(args) > 0 {
|
||||
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{
|
||||
cmdDownload,
|
||||
cmdEdit,
|
||||
cmdEditwork,
|
||||
cmdGraph,
|
||||
cmdInit,
|
||||
cmdInitwork,
|
||||
cmdTidy,
|
||||
cmdVendor,
|
||||
cmdVerify,
|
||||
|
|
|
|||
|
|
@ -74,7 +74,7 @@ func runVendor(ctx context.Context, cmd *base.Command, args []string) {
|
|||
}
|
||||
_, pkgs := modload.LoadPackages(ctx, loadOpts, "all")
|
||||
|
||||
vdir := filepath.Join(modload.ModRoot(), "vendor")
|
||||
vdir := filepath.Join(modload.VendorDir())
|
||||
if err := os.RemoveAll(vdir); err != nil {
|
||||
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)
|
||||
for _, pkg := range pkgs {
|
||||
m := modload.PackageModule(pkg)
|
||||
if m.Path == "" || m == modload.Target {
|
||||
if m.Path == "" || m.Version == "" && modload.MainModules.Contains(m.Path) {
|
||||
continue
|
||||
}
|
||||
modpkgs[m] = append(modpkgs[m], pkg)
|
||||
|
|
@ -128,7 +128,8 @@ func runVendor(ctx context.Context, cmd *base.Command, args []string) {
|
|||
}
|
||||
|
||||
for _, m := range vendorMods {
|
||||
line := moduleLine(m, modload.Replacement(m))
|
||||
replacement, _ := modload.Replacement(m)
|
||||
line := moduleLine(m, replacement)
|
||||
io.WriteString(w, line)
|
||||
|
||||
goVersion := ""
|
||||
|
|
|
|||
|
|
@ -39,9 +39,12 @@ See https://golang.org/ref/mod#go-mod-verify for more about 'go mod verify'.
|
|||
|
||||
func init() {
|
||||
base.AddModCommonFlags(&cmdVerify.Flag)
|
||||
base.AddWorkfileFlag(&cmdVerify.Flag)
|
||||
}
|
||||
|
||||
func runVerify(ctx context.Context, cmd *base.Command, args []string) {
|
||||
modload.InitWorkfile()
|
||||
|
||||
if len(args) != 0 {
|
||||
// NOTE(rsc): Could take a module pattern.
|
||||
base.Fatalf("go mod verify: verify takes no arguments")
|
||||
|
|
|
|||
|
|
@ -61,9 +61,11 @@ var (
|
|||
func init() {
|
||||
cmdWhy.Run = runWhy // break init cycle
|
||||
base.AddModCommonFlags(&cmdWhy.Flag)
|
||||
base.AddWorkfileFlag(&cmdWhy.Flag)
|
||||
}
|
||||
|
||||
func runWhy(ctx context.Context, cmd *base.Command, args []string) {
|
||||
modload.InitWorkfile()
|
||||
modload.ForceUseModules = true
|
||||
modload.RootMode = modload.NeedRoot
|
||||
|
||||
|
|
|
|||
|
|
@ -693,19 +693,21 @@ func isValidSum(data []byte) bool {
|
|||
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.
|
||||
//
|
||||
// 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
|
||||
// (version ends with "/go.mod"). Existing sums will be preserved unless they
|
||||
// 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()
|
||||
defer goSum.mu.Unlock()
|
||||
|
||||
// If we haven't read the go.sum file yet, don't bother writing it.
|
||||
if !goSum.enabled {
|
||||
return
|
||||
return nil
|
||||
}
|
||||
|
||||
// Check whether we need to add sums for which keep[m] is true or remove
|
||||
|
|
@ -723,10 +725,10 @@ Outer:
|
|||
}
|
||||
}
|
||||
if !dirty {
|
||||
return
|
||||
return nil
|
||||
}
|
||||
if cfg.BuildMod == "readonly" {
|
||||
base.Fatalf("go: updates to go.sum needed, disabled by -mod=readonly")
|
||||
if readonly {
|
||||
return ErrGoSumDirty
|
||||
}
|
||||
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")
|
||||
|
|
@ -774,11 +776,12 @@ Outer:
|
|||
})
|
||||
|
||||
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.overwrite = false
|
||||
return nil
|
||||
}
|
||||
|
||||
// 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
|
||||
for _, pkg := range pkgs {
|
||||
if pkg.Name == "main" && pkg.Module != nil && pkg.Module.Path != modload.Target.Path {
|
||||
haveExternalExe = true
|
||||
break
|
||||
if pkg.Name == "main" && pkg.Module != nil {
|
||||
if !modload.MainModules.Contains(pkg.Module.Path) {
|
||||
haveExternalExe = true
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
if haveExternalExe {
|
||||
|
|
@ -675,7 +677,9 @@ func (r *resolver) queryNone(ctx context.Context, q *query) {
|
|||
|
||||
if !q.isWildcard() {
|
||||
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
|
||||
// version "none". This is not an entirely unreasonable request: it
|
||||
// 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
|
||||
// plain meaning of the query. To try to reduce confusion, reject the
|
||||
// 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"}}
|
||||
|
|
@ -698,8 +702,8 @@ func (r *resolver) queryNone(ctx context.Context, q *query) {
|
|||
continue
|
||||
}
|
||||
q.pathOnce(curM.Path, func() pathSet {
|
||||
if modload.HasModRoot() && curM == modload.Target {
|
||||
return errSet(&modload.QueryMatchesMainModuleError{Pattern: q.pattern, Query: q.version})
|
||||
if modload.HasModRoot() && curM.Version == "" && modload.MainModules.Contains(curM.Path) {
|
||||
return errSet(&modload.QueryMatchesMainModulesError{MainModules: []module.Version{curM}, Pattern: q.pattern, Query: q.version})
|
||||
}
|
||||
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
|
||||
// restricted to matching packages in the main module.
|
||||
pkgPattern := modload.DirImportPath(ctx, q.pattern)
|
||||
pkgPattern, mainModule := modload.MainModules.DirImportPath(ctx, q.pattern)
|
||||
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 {
|
||||
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"))
|
||||
}
|
||||
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})
|
||||
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{}
|
||||
}
|
||||
|
||||
if curM.Path == modload.Target.Path && !versionOkForMainModule(q.version) {
|
||||
if modload.MainModules.Contains(curM.Path) && !versionOkForMainModule(q.version) {
|
||||
if q.matchesPath(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,
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -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 {
|
||||
if m.Path == "" || m == modload.Target {
|
||||
// Packages in the standard library and main module are already at their
|
||||
if m.Path == "" || m.Version == "" && modload.MainModules.Contains(m.Path) {
|
||||
// Packages in the standard library and main modules are already at their
|
||||
// latest (and only) available versions.
|
||||
return nil
|
||||
}
|
||||
|
|
@ -1370,11 +1385,11 @@ func (r *resolver) disambiguate(cs pathSet) (filtered pathSet, isPackage bool, m
|
|||
continue
|
||||
}
|
||||
|
||||
if m.Path == modload.Target.Path {
|
||||
if m.Version == modload.Target.Version {
|
||||
if modload.MainModules.Contains(m.Path) {
|
||||
if m.Version == "" {
|
||||
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
|
||||
}
|
||||
|
||||
|
|
@ -1610,7 +1625,7 @@ func (r *resolver) checkPackageProblems(ctx context.Context, pkgPatterns []strin
|
|||
i := i
|
||||
m := r.buildList[i]
|
||||
mActual := m
|
||||
if mRepl := modload.Replacement(m); mRepl.Path != "" {
|
||||
if mRepl, _ := modload.Replacement(m); mRepl.Path != "" {
|
||||
mActual = mRepl
|
||||
}
|
||||
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
|
||||
}
|
||||
oldActual := old
|
||||
if oldRepl := modload.Replacement(old); oldRepl.Path != "" {
|
||||
if oldRepl, _ := modload.Replacement(old); oldRepl.Path != "" {
|
||||
oldActual = oldRepl
|
||||
}
|
||||
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")
|
||||
}
|
||||
|
||||
if m.Path == modload.Target.Path && m.Version != modload.Target.Version {
|
||||
reportError(q, &modload.QueryMatchesMainModuleError{
|
||||
Pattern: q.pattern,
|
||||
Query: q.version,
|
||||
if modload.MainModules.Contains(m.Path) && m.Version != "" {
|
||||
reportError(q, &modload.QueryMatchesMainModulesError{
|
||||
MainModules: []module.Version{{Path: m.Path}},
|
||||
Pattern: q.pattern,
|
||||
Query: q.version,
|
||||
})
|
||||
return
|
||||
}
|
||||
|
|
@ -1775,7 +1791,7 @@ func (r *resolver) updateBuildList(ctx context.Context, additions []module.Versi
|
|||
|
||||
resolved := make([]module.Version, 0, len(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})
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -192,9 +192,9 @@ func (q *query) validate() error {
|
|||
// TODO(bcmills): "all@none" seems like a totally reasonable way to
|
||||
// request that we remove all module requirements, leaving only the main
|
||||
// module and standard library. Perhaps we should implement that someday.
|
||||
return &modload.QueryMatchesMainModuleError{
|
||||
Pattern: q.pattern,
|
||||
Query: q.version,
|
||||
return &modload.QueryUpgradesAllError{
|
||||
MainModules: modload.MainModules.Versions(),
|
||||
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
|
||||
// graph).
|
||||
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{
|
||||
Path: m.Path,
|
||||
Version: m.Version,
|
||||
Main: true,
|
||||
}
|
||||
if v, ok := rawGoVersion.Load(Target); ok {
|
||||
if v, ok := rawGoVersion.Load(m); ok {
|
||||
info.GoVersion = v.(string)
|
||||
} else {
|
||||
panic("internal error: GoVersion not set for main module")
|
||||
}
|
||||
if HasModRoot() {
|
||||
info.Dir = ModRoot()
|
||||
info.GoMod = ModFilePath()
|
||||
if modRoot := MainModules.ModRoot(m); modRoot != "" {
|
||||
info.Dir = modRoot
|
||||
info.GoMod = modFilePath(modRoot)
|
||||
}
|
||||
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 := func(m *modinfo.ModulePublic) {
|
||||
completeFromModCache := func(m *modinfo.ModulePublic, replacedFrom string) {
|
||||
checksumOk := func(suffix string) bool {
|
||||
return rs == nil || m.Version == "" || cfg.BuildMod == "mod" ||
|
||||
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") {
|
||||
// Load the go.mod file to determine the Go version, since it hasn't
|
||||
// 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
|
||||
}
|
||||
}
|
||||
|
|
@ -289,11 +289,11 @@ func moduleInfo(ctx context.Context, rs *Requirements, m module.Version, mode Li
|
|||
if rs == nil {
|
||||
// If this was an explicitly-versioned argument to 'go mod download' or
|
||||
// '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
|
||||
}
|
||||
|
||||
r := Replacement(m)
|
||||
r, replacedFrom := Replacement(m)
|
||||
if r.Path == "" {
|
||||
if cfg.BuildMod == "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
|
||||
// prefix of the other.
|
||||
} else {
|
||||
completeFromModCache(info)
|
||||
completeFromModCache(info, "")
|
||||
}
|
||||
return info
|
||||
}
|
||||
|
|
@ -322,12 +322,12 @@ func moduleInfo(ctx context.Context, rs *Requirements, m module.Version, mode Li
|
|||
if filepath.IsAbs(r.Path) {
|
||||
info.Replace.Dir = r.Path
|
||||
} 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")
|
||||
}
|
||||
if cfg.BuildMod != "vendor" {
|
||||
completeFromModCache(info.Replace)
|
||||
completeFromModCache(info.Replace, replacedFrom)
|
||||
info.Dir = info.Replace.Dir
|
||||
info.GoMod = info.Replace.GoMod
|
||||
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
|
||||
// name packages that were resolved successfully with LoadPackages.
|
||||
func PackageBuildInfo(path string, deps []string) string {
|
||||
if isStandardImportPath(path) || !Enabled() {
|
||||
if !Enabled() {
|
||||
return ""
|
||||
}
|
||||
|
||||
target := mustFindModule(loaded, path, path)
|
||||
target, _ := findModule(loaded, path)
|
||||
mdeps := make(map[module.Version]bool)
|
||||
for _, dep := range deps {
|
||||
if !isStandardImportPath(dep) {
|
||||
mdeps[mustFindModule(loaded, path, dep)] = true
|
||||
if m, ok := findModule(loaded, dep); ok {
|
||||
mdeps[m] = true
|
||||
}
|
||||
}
|
||||
var mods []module.Version
|
||||
|
|
@ -367,14 +366,16 @@ func PackageBuildInfo(path string, deps []string) string {
|
|||
mv = "(devel)"
|
||||
}
|
||||
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))
|
||||
} else {
|
||||
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 {
|
||||
writeEntry("dep", mod)
|
||||
}
|
||||
|
|
@ -382,38 +383,13 @@ func PackageBuildInfo(path string, deps []string) 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.
|
||||
// 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) {
|
||||
if pkg, ok := ld.pkgCache.Get(path).(*loadPkg); ok {
|
||||
return pkg.mod, pkg.mod != module.Version{}
|
||||
}
|
||||
if path == "command-line-arguments" {
|
||||
return Target, true
|
||||
}
|
||||
return module.Version{}, false
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ type Requirements struct {
|
|||
depth modDepth
|
||||
|
||||
// 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.
|
||||
rootModules []module.Version
|
||||
maxRootVersion map[string]string
|
||||
|
|
@ -99,8 +99,8 @@ var requirements *Requirements
|
|||
// *Requirements before any other method.
|
||||
func newRequirements(depth modDepth, rootModules []module.Version, direct map[string]bool) *Requirements {
|
||||
for i, m := range rootModules {
|
||||
if m == Target {
|
||||
panic(fmt.Sprintf("newRequirements called with untrimmed build list: rootModules[%v] is Target", i))
|
||||
if m.Version == "" && MainModules.Contains(m.Path) {
|
||||
panic(fmt.Sprintf("newRequirements called with untrimmed build list: rootModules[%v] is a main module", i))
|
||||
}
|
||||
if m.Path == "" || m.Version == "" {
|
||||
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) {
|
||||
rs.graphOnce.Do(func() {
|
||||
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 {
|
||||
// The roots of a lazy module should already include every module in the
|
||||
// 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
|
||||
// out”, like a more aggressive version of lazy loading: in vendor mode,
|
||||
// the root requirements *are* the complete module graph.
|
||||
mg.g.Require(Target, rs.rootModules)
|
||||
mg.g.Require(mainModule, rs.rootModules)
|
||||
} else {
|
||||
// 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
|
||||
|
|
@ -170,7 +175,7 @@ func (rs *Requirements) initVendor(vendorList []module.Version) {
|
|||
// graph, but still distinguishes between direct and indirect
|
||||
// dependencies.
|
||||
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)
|
||||
}
|
||||
|
||||
|
|
@ -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
|
||||
// dependency.
|
||||
func (rs *Requirements) rootSelected(path string) (version string, ok bool) {
|
||||
if path == Target.Path {
|
||||
return Target.Version, true
|
||||
if MainModules.Contains(path) {
|
||||
return "", true
|
||||
}
|
||||
if v, ok := rs.maxRootVersion[path]; ok {
|
||||
return v, true
|
||||
|
|
@ -197,7 +202,7 @@ func (rs *Requirements) rootSelected(path string) (version string, ok bool) {
|
|||
// selection.
|
||||
func (rs *Requirements) hasRedundantRoot() bool {
|
||||
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
|
||||
}
|
||||
}
|
||||
|
|
@ -274,10 +279,17 @@ func readModGraph(ctx context.Context, depth modDepth, roots []module.Version) (
|
|||
mu sync.Mutex // guards mg.g and hasError during loading
|
||||
hasError bool
|
||||
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 (
|
||||
loadQueue = par.NewQueue(runtime.GOMAXPROCS(0))
|
||||
|
|
@ -404,10 +416,12 @@ func (mg *ModuleGraph) findError() error {
|
|||
}
|
||||
|
||||
func (mg *ModuleGraph) allRootsSelected() bool {
|
||||
roots, _ := mg.g.RequiredBy(Target)
|
||||
for _, m := range roots {
|
||||
if mg.Selected(m.Path) != m.Version {
|
||||
return false
|
||||
for _, mm := range MainModules.Versions() {
|
||||
roots, _ := mg.g.RequiredBy(mm)
|
||||
for _, m := range roots {
|
||||
if mg.Selected(m.Path) != m.Version {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
|
|
@ -447,7 +461,7 @@ func LoadModGraph(ctx context.Context, goVersion string) *ModuleGraph {
|
|||
base.Fatalf("go: %v", err)
|
||||
}
|
||||
|
||||
commitRequirements(ctx, modFileGoVersion(), rs)
|
||||
commitRequirements(ctx, rs)
|
||||
return mg
|
||||
}
|
||||
|
||||
|
|
@ -513,7 +527,7 @@ func EditBuildList(ctx context.Context, add, mustSelect []module.Version) (chang
|
|||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
commitRequirements(ctx, modFileGoVersion(), rs)
|
||||
commitRequirements(ctx, rs)
|
||||
return changed, err
|
||||
}
|
||||
|
||||
|
|
@ -546,10 +560,11 @@ type Conflict struct {
|
|||
// both retain the same versions of all packages in pkgs and satisfy the
|
||||
// lazy loading invariants (if applicable).
|
||||
func tidyRoots(ctx context.Context, rs *Requirements, pkgs []*loadPkg) (*Requirements, error) {
|
||||
mainModule := MainModules.mustGetSingleMainModule()
|
||||
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) {
|
||||
|
|
@ -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
|
||||
// add any needed roots from the tidy root set (without removing existing untidy
|
||||
// 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 (
|
||||
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".
|
||||
//
|
||||
|
|
@ -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
|
||||
// graph so that we can update those roots to be consistent with other
|
||||
// requirements.
|
||||
if cfg.BuildMod != "mod" {
|
||||
if mustHaveCompleteRequirements() {
|
||||
// Our changes to the roots may have moved dependencies into or out of
|
||||
// the lazy-loading horizon, which could in turn change the selected
|
||||
// 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))
|
||||
rootsUpgraded = false
|
||||
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 {
|
||||
if inRootPaths[m.Path] {
|
||||
// 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
|
||||
// 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.
|
||||
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 (
|
||||
keep []module.Version
|
||||
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 {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -1011,7 +1028,7 @@ func updateEagerRoots(ctx context.Context, direct map[string]bool, rs *Requireme
|
|||
return rs, err
|
||||
}
|
||||
|
||||
if cfg.BuildMod != "mod" {
|
||||
if mustHaveCompleteRequirements() {
|
||||
// Instead of actually updating the requirements, just check that no updates
|
||||
// are needed.
|
||||
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,
|
||||
// the choice of explicit vs. implicit dependency has no impact on MVS
|
||||
// selection (for itself or any other module).
|
||||
keep := append(mg.BuildList()[1:], add...)
|
||||
keep := append(mg.BuildList()[MainModules.Len():], add...)
|
||||
for _, m := range keep {
|
||||
if direct[m.Path] && !inRootPaths[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})
|
||||
if err != nil {
|
||||
return rs, err
|
||||
// TODO(matloob): Make roots into a map.
|
||||
var roots []module.Version
|
||||
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
|
||||
// preserve its cached ModuleGraph (if any).
|
||||
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.
|
||||
|
|
@ -1117,5 +1143,5 @@ func convertDepth(ctx context.Context, rs *Requirements, depth modDepth) (*Requi
|
|||
if err != nil {
|
||||
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.
|
||||
var rootPaths []string
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
|
@ -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 {
|
||||
return nil, false, err
|
||||
}
|
||||
|
|
@ -218,8 +218,8 @@ func raiseLimitsForUpgrades(ctx context.Context, maxVersion map[string]string, d
|
|||
eagerUpgrades = tryUpgrade
|
||||
} else {
|
||||
for _, m := range tryUpgrade {
|
||||
if m.Path == Target.Path {
|
||||
// Target is already considered to be higher than any possible m, so we
|
||||
if MainModules.Contains(m.Path) {
|
||||
// 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
|
||||
// dependencies.
|
||||
continue
|
||||
|
|
@ -318,7 +318,7 @@ func selectPotentiallyImportedModules(ctx context.Context, limiter *versionLimit
|
|||
|
||||
mods = make([]module.Version, 0, len(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})
|
||||
}
|
||||
}
|
||||
|
|
@ -334,7 +334,7 @@ func selectPotentiallyImportedModules(ctx context.Context, limiter *versionLimit
|
|||
}
|
||||
mods = make([]module.Version, 0, len(limiter.selected))
|
||||
for path, _ := range limiter.selected {
|
||||
if path != Target.Path {
|
||||
if !MainModules.Contains(path) {
|
||||
if v := mg.Selected(path); v != "none" {
|
||||
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
|
||||
// requirements.
|
||||
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{
|
||||
depth: depth,
|
||||
max: max,
|
||||
selected: map[string]string{Target.Path: Target.Version},
|
||||
selected: selected,
|
||||
dqReason: map[module.Version]dqState{},
|
||||
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
|
||||
// marginally relevant at best.
|
||||
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
|
||||
// tautological.
|
||||
return dqState{}
|
||||
|
|
|
|||
|
|
@ -32,6 +32,8 @@ type ImportMissingError struct {
|
|||
Module module.Version
|
||||
QueryErr error
|
||||
|
||||
ImportingMainModule module.Version
|
||||
|
||||
// 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
|
||||
// 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 {
|
||||
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)
|
||||
}
|
||||
|
||||
|
|
@ -257,11 +262,13 @@ func importFromModules(ctx context.Context, path string, rs *Requirements, mg *M
|
|||
// Is the package in the standard library?
|
||||
pathIsStd := search.IsStandardImportPath(path)
|
||||
if pathIsStd && goroot.IsStandardPackage(cfg.GOROOT, cfg.BuildContext.Compiler, path) {
|
||||
if targetInGorootSrc {
|
||||
if dir, ok, err := dirInModule(path, targetPrefix, ModRoot(), true); err != nil {
|
||||
return module.Version{}, dir, err
|
||||
} else if ok {
|
||||
return Target, dir, nil
|
||||
for _, mainModule := range MainModules.Versions() {
|
||||
if MainModules.InGorootSrc(mainModule) {
|
||||
if dir, ok, err := dirInModule(path, MainModules.PathPrefix(mainModule), MainModules.ModRoot(mainModule), true); err != nil {
|
||||
return module.Version{}, dir, err
|
||||
} else if ok {
|
||||
return mainModule, dir, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
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.
|
||||
// Everything must be in the main module or the main module's vendor directory.
|
||||
if cfg.BuildMod == "vendor" {
|
||||
mainDir, mainOK, mainErr := dirInModule(path, targetPrefix, ModRoot(), true)
|
||||
vendorDir, vendorOK, _ := dirInModule(path, "", filepath.Join(ModRoot(), "vendor"), false)
|
||||
mainModule := MainModules.mustGetSingleMainModule()
|
||||
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 {
|
||||
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.
|
||||
// We'll leave that for load.
|
||||
if !vendorOK && mainDir != "" {
|
||||
return Target, mainDir, nil
|
||||
return mainModule, mainDir, nil
|
||||
}
|
||||
if mainErr != nil {
|
||||
return module.Version{}, "", mainErr
|
||||
}
|
||||
readVendorList()
|
||||
readVendorList(mainModule)
|
||||
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) {
|
||||
// To avoid spurious remote fetches, try the latest replacement for each
|
||||
// module (golang.org/issue/26241).
|
||||
if index != nil {
|
||||
var mods []module.Version
|
||||
for mp, mv := range index.highestReplaced {
|
||||
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")
|
||||
var mods []module.Version
|
||||
for _, v := range MainModules.Versions() {
|
||||
if index := MainModules.Index(v); index != nil {
|
||||
for mp, mv := range index.highestReplaced {
|
||||
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")
|
||||
}
|
||||
}
|
||||
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.
|
||||
// As in QueryPattern, prefer the longest prefix that satisfies the import.
|
||||
sort.Slice(mods, func(i, j int) bool {
|
||||
return len(mods[i].Path) > len(mods[j].Path)
|
||||
})
|
||||
for _, m := range mods {
|
||||
needSum := true
|
||||
root, isLocal, err := fetch(ctx, m, needSum)
|
||||
if err != nil {
|
||||
if sumErr := (*sumMissingError)(nil); errors.As(err, &sumErr) {
|
||||
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
|
||||
// Every module path in mods is a prefix of the import path.
|
||||
// As in QueryPattern, prefer the longest prefix that satisfies the import.
|
||||
sort.Slice(mods, func(i, j int) bool {
|
||||
return len(mods[i].Path) > len(mods[j].Path)
|
||||
})
|
||||
for _, m := range mods {
|
||||
needSum := true
|
||||
root, isLocal, err := fetch(ctx, m, needSum)
|
||||
if err != nil {
|
||||
if sumErr := (*sumMissingError)(nil); errors.As(err, &sumErr) {
|
||||
return module.Version{}, &ImportMissingSumError{importPath: path}
|
||||
}
|
||||
return module.Version{}, err
|
||||
}
|
||||
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.
|
||||
return module.Version{}, &PackageNotInModuleError{
|
||||
Mod: mods[0],
|
||||
Query: "latest",
|
||||
Pattern: path,
|
||||
Replacement: Replacement(mods[0]),
|
||||
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
|
||||
}
|
||||
}
|
||||
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,
|
||||
// if any, is local to the filesystem.
|
||||
func fetch(ctx context.Context, mod module.Version, needSum bool) (dir string, isLocal bool, err error) {
|
||||
if mod == Target {
|
||||
return ModRoot(), true, nil
|
||||
if modRoot := MainModules.ModRoot(mod); modRoot != "" {
|
||||
return modRoot, true, nil
|
||||
}
|
||||
if r := Replacement(mod); r.Path != "" {
|
||||
if r, replacedFrom := Replacement(mod); r.Path != "" {
|
||||
if r.Version == "" {
|
||||
dir = r.Path
|
||||
if !filepath.IsAbs(dir) {
|
||||
dir = filepath.Join(ModRoot(), dir)
|
||||
dir = filepath.Join(replacedFrom, dir)
|
||||
}
|
||||
// Ensure that the replacement directory actually exists:
|
||||
// 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
|
||||
}
|
||||
|
||||
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{})
|
||||
}
|
||||
|
||||
|
|
|
|||
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 {
|
||||
commitRequirements(ctx, modFileGoVersion(), rs)
|
||||
commitRequirements(ctx, rs)
|
||||
}
|
||||
return mods, err
|
||||
}
|
||||
|
||||
func listModules(ctx context.Context, rs *Requirements, args []string, mode ListMode) (_ *Requirements, mods []*modinfo.ModulePublic, mgErr error) {
|
||||
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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
// indicates that.
|
||||
ModRoot()
|
||||
if !HasModRoot() {
|
||||
die()
|
||||
}
|
||||
|
||||
if ld != nil {
|
||||
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.
|
||||
// loadFromRoots will expand that to "all".
|
||||
m.Errs = m.Errs[:0]
|
||||
matchPackages(ctx, m, opts.Tags, omitStd, []module.Version{Target})
|
||||
matchPackages(ctx, m, opts.Tags, omitStd, MainModules.Versions())
|
||||
} else {
|
||||
// Starting with the packages in the main module,
|
||||
// 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
|
||||
// preserve checksums for) additional entities from compatRS, which are
|
||||
// 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.
|
||||
loaded = ld
|
||||
commitRequirements(ctx, loaded.GoVersion, loaded.requirements)
|
||||
commitRequirements(ctx, loaded.requirements)
|
||||
|
||||
for _, pkg := range ld.pkgs {
|
||||
if !pkg.isTest() {
|
||||
|
|
@ -436,14 +446,23 @@ func matchLocalDirs(ctx context.Context, m *search.Match, rs *Requirements) {
|
|||
if !filepath.IsAbs(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.AddError(fmt.Errorf("directory prefix %s outside available modules", base.ShortPath(absDir)))
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
m.MatchDirs()
|
||||
m.MatchDirs(modRoots)
|
||||
}
|
||||
|
||||
// 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 {
|
||||
if absDir == cfg.GOROOTsrc {
|
||||
return "", errPkgIsGorootSrc
|
||||
for _, mod := range MainModules.Versions() {
|
||||
modRoot := MainModules.ModRoot(mod)
|
||||
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
|
||||
// the module cache directories (formerly GOPATH/src/mod/foo@v1.5.2/bar).
|
||||
// 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):], "@") {
|
||||
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)
|
||||
var pkgNotFoundErr error
|
||||
pkgNotFoundLongestPrefix := ""
|
||||
for _, mainModule := range MainModules.Versions() {
|
||||
modRoot := MainModules.ModRoot(mainModule)
|
||||
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()
|
||||
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)
|
||||
mainModulePrefix := MainModules.PathPrefix(mainModule)
|
||||
if mainModulePrefix == "" {
|
||||
pkg := strings.TrimPrefix(suffix, "/")
|
||||
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
|
||||
}
|
||||
|
||||
if targetPrefix == "" {
|
||||
pkg := strings.TrimPrefix(suffix, "/")
|
||||
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 pkgNotFoundErr != nil {
|
||||
return "", pkgNotFoundErr
|
||||
}
|
||||
|
||||
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) {
|
||||
var root string
|
||||
var err error
|
||||
if repl := Replacement(m); repl.Path != "" && repl.Version == "" {
|
||||
if repl, replModRoot := Replacement(m); repl.Path != "" && repl.Version == "" {
|
||||
root = repl.Path
|
||||
if !filepath.IsAbs(root) {
|
||||
root = filepath.Join(ModRoot(), root)
|
||||
root = filepath.Join(replModRoot, root)
|
||||
}
|
||||
} else if repl.Path != "" {
|
||||
root, err = modfetch.DownloadDir(repl)
|
||||
|
|
@ -645,14 +684,14 @@ func ImportFromFiles(ctx context.Context, gofiles []string) {
|
|||
return roots
|
||||
},
|
||||
})
|
||||
commitRequirements(ctx, loaded.GoVersion, loaded.requirements)
|
||||
commitRequirements(ctx, loaded.requirements)
|
||||
}
|
||||
|
||||
// DirImportPath returns the effective import path for dir,
|
||||
// provided it is within the main module, or else returns ".".
|
||||
func DirImportPath(ctx context.Context, dir string) string {
|
||||
// provided it is within a main module, or else returns ".".
|
||||
func (mms *MainModuleSet) DirImportPath(ctx context.Context, dir string) (path string, m module.Version) {
|
||||
if !HasModRoot() {
|
||||
return "."
|
||||
return ".", module.Version{}
|
||||
}
|
||||
LoadModFile(ctx) // Sets targetPrefix.
|
||||
|
||||
|
|
@ -662,17 +701,32 @@ func DirImportPath(ctx context.Context, dir string) string {
|
|||
dir = filepath.Clean(dir)
|
||||
}
|
||||
|
||||
if dir == modRoot {
|
||||
return targetPrefix
|
||||
}
|
||||
if strings.HasPrefix(dir, modRoot+string(filepath.Separator)) {
|
||||
suffix := filepath.ToSlash(dir[len(modRoot):])
|
||||
if strings.HasPrefix(suffix, "/vendor/") {
|
||||
return strings.TrimPrefix(suffix, "/vendor/")
|
||||
var longestPrefix string
|
||||
var longestPrefixPath string
|
||||
var longestPrefixVersion module.Version
|
||||
for _, v := range mms.Versions() {
|
||||
modRoot := mms.ModRoot(v)
|
||||
if dir == modRoot {
|
||||
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
|
||||
|
|
@ -894,10 +948,7 @@ func (pkg *loadPkg) fromExternalModule() bool {
|
|||
if pkg.mod.Path == "" {
|
||||
return false // loaded from the standard library, not a module
|
||||
}
|
||||
if pkg.mod.Path == Target.Path {
|
||||
return false // loaded from the main module.
|
||||
}
|
||||
return true
|
||||
return !MainModules.Contains(pkg.mod.Path)
|
||||
}
|
||||
|
||||
var errMissing = errors.New("cannot find package")
|
||||
|
|
@ -915,7 +966,7 @@ func loadFromRoots(ctx context.Context, params loaderParams) *loader {
|
|||
}
|
||||
|
||||
if ld.GoVersion == "" {
|
||||
ld.GoVersion = modFileGoVersion()
|
||||
ld.GoVersion = MainModules.GoVersion()
|
||||
|
||||
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())
|
||||
|
|
@ -1168,7 +1219,7 @@ func (ld *loader) updateRequirements(ctx context.Context) (changed bool, err err
|
|||
}
|
||||
|
||||
for _, pkg := range ld.pkgs {
|
||||
if pkg.mod != Target {
|
||||
if pkg.mod.Version != "" || !MainModules.Contains(pkg.mod.Path) {
|
||||
continue
|
||||
}
|
||||
for _, dep := range pkg.imports {
|
||||
|
|
@ -1327,6 +1378,15 @@ func (ld *loader) resolveMissingImports(ctx context.Context) (modAddedBy map[mod
|
|||
var err error
|
||||
mod, err = queryImport(ctx, pkg.path, ld.requirements)
|
||||
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
|
||||
// for pkg to either the original error or the one returned by
|
||||
// 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.
|
||||
wantTest := false
|
||||
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
|
||||
// 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.
|
||||
|
|
@ -1446,7 +1506,7 @@ func (ld *loader) applyPkgFlags(ctx context.Context, pkg *loadPkg, flags loadPkg
|
|||
|
||||
if wantTest {
|
||||
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
|
||||
// they cause the packages they import to also be in "all". So are tests
|
||||
// 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 == "" {
|
||||
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
|
||||
// package that is *only* imported by other packages in "all" is always
|
||||
// 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 !ld.VendorModulesInGOROOTSrc || Target.Path != "cmd" {
|
||||
if !ld.VendorModulesInGOROOTSrc || !MainModules.Contains("cmd") {
|
||||
vendorPath := pathpkg.Join("cmd", "vendor", path)
|
||||
|
||||
if _, err := os.Stat(filepath.Join(cfg.GOROOTsrc, filepath.FromSlash(vendorPath))); err == nil {
|
||||
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'
|
||||
// to the vendor directory.
|
||||
//
|
||||
|
|
@ -1753,7 +1814,7 @@ func (ld *loader) checkMultiplePaths() {
|
|||
|
||||
firstPath := map[module.Version]string{}
|
||||
for _, mod := range mods {
|
||||
src := resolveReplacement(mod)
|
||||
src, _ := resolveReplacement(mod)
|
||||
if prev, ok := firstPath[src]; !ok {
|
||||
firstPath[src] = mod.Path
|
||||
} else if prev != mod.Path {
|
||||
|
|
@ -1781,7 +1842,7 @@ func (ld *loader) checkTidyCompatibility(ctx context.Context, rs *Requirements)
|
|||
fmt.Fprintln(os.Stderr)
|
||||
|
||||
goFlag := ""
|
||||
if ld.GoVersion != modFileGoVersion() {
|
||||
if ld.GoVersion != MainModules.GoVersion() {
|
||||
goFlag = " -go=" + ld.GoVersion
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -56,11 +56,9 @@ const (
|
|||
go117LazyTODO = false
|
||||
)
|
||||
|
||||
var modFile *modfile.File
|
||||
|
||||
// modFileGoVersion returns the (non-empty) Go version at which the requirements
|
||||
// in modFile are intepreted, or the latest Go version if modFile is nil.
|
||||
func modFileGoVersion() string {
|
||||
// in modFile are interpreted, or the latest Go version if modFile is nil.
|
||||
func modFileGoVersion(modFile *modfile.File) string {
|
||||
if modFile == nil {
|
||||
return LatestGoVersion()
|
||||
}
|
||||
|
|
@ -92,9 +90,6 @@ type modFileIndex struct {
|
|||
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 {
|
||||
indirect bool
|
||||
}
|
||||
|
|
@ -137,8 +132,10 @@ var ErrDisallowed = errors.New("disallowed module version")
|
|||
// CheckExclusions returns an error equivalent to ErrDisallowed if module m is
|
||||
// excluded by the main module's go.mod file.
|
||||
func CheckExclusions(ctx context.Context, m module.Version) error {
|
||||
if index != nil && index.exclude[m] {
|
||||
return module.VersionError(m, errExcluded)
|
||||
for _, mainModule := range MainModules.Versions() {
|
||||
if index := MainModules.Index(mainModule); index != nil && index.exclude[m] {
|
||||
return module.VersionError(m, errExcluded)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
@ -170,7 +167,7 @@ func CheckRetractions(ctx context.Context, m module.Version) (err error) {
|
|||
// Cannot be retracted.
|
||||
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.
|
||||
// Don't load retractions, since we'd just load the replacement.
|
||||
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
|
||||
// path that we expect if the module or its repository was renamed.
|
||||
// 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 {
|
||||
return err
|
||||
}
|
||||
summary, err := rawGoModSummary(rm)
|
||||
summary, err := rawGoModSummary(rm, replacedFrom)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -289,51 +286,72 @@ func CheckDeprecation(ctx context.Context, m module.Version) (deprecation string
|
|||
// Don't look up deprecation.
|
||||
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.
|
||||
// We'll look up deprecation separately for the replacement.
|
||||
return "", nil
|
||||
}
|
||||
|
||||
latest, err := queryLatestVersionIgnoringRetractions(ctx, m.Path)
|
||||
latest, replacedFrom, err := queryLatestVersionIgnoringRetractions(ctx, m.Path)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
summary, err := rawGoModSummary(latest)
|
||||
summary, err := rawGoModSummary(latest, replacedFrom)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
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
|
||||
// a module.Version with Path == "".
|
||||
func Replacement(mod module.Version) module.Version {
|
||||
if index != nil {
|
||||
if r, ok := index.replace[mod]; ok {
|
||||
return r
|
||||
}
|
||||
if r, ok := index.replace[module.Version{Path: mod.Path}]; ok {
|
||||
return r
|
||||
func Replacement(mod module.Version) (module.Version, string) {
|
||||
_ = TODOWorkspaces("Support replaces in the go.work file.")
|
||||
foundFrom, found, foundModRoot := "", module.Version{}, ""
|
||||
for _, v := range MainModules.Versions() {
|
||||
if index := MainModules.Index(v); index != nil {
|
||||
if from, r, ok := replacement(mod, index); ok {
|
||||
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
|
||||
// for m: either m itself, or the replacement for m (iff m is replaced).
|
||||
func resolveReplacement(m module.Version) module.Version {
|
||||
if r := Replacement(m); r.Path != "" {
|
||||
return r
|
||||
// It also returns the modroot of the module providing the replacement if
|
||||
// one was found.
|
||||
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.
|
||||
// If modFile has been changed since it was first read,
|
||||
// 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.data = data
|
||||
i.dataNeedsFix = needsFix
|
||||
|
|
@ -345,12 +363,12 @@ func indexModFile(data []byte, modFile *modfile.File, needsFix bool) *modFileInd
|
|||
|
||||
i.goVersionV = ""
|
||||
if modFile.Go == nil {
|
||||
rawGoVersion.Store(Target, "")
|
||||
rawGoVersion.Store(mod, "")
|
||||
} else {
|
||||
// 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.
|
||||
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))
|
||||
|
|
@ -490,8 +508,8 @@ type retraction struct {
|
|||
//
|
||||
// The caller must not modify the returned summary.
|
||||
func goModSummary(m module.Version) (*modFileSummary, error) {
|
||||
if m == Target {
|
||||
panic("internal error: goModSummary called on the Target module")
|
||||
if m.Version == "" && MainModules.Contains(m.Path) {
|
||||
panic("internal error: goModSummary called on a main module")
|
||||
}
|
||||
|
||||
if cfg.BuildMod == "vendor" {
|
||||
|
|
@ -506,7 +524,7 @@ func goModSummary(m module.Version) (*modFileSummary, error) {
|
|||
|
||||
// For every module other than the target,
|
||||
// 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,
|
||||
// so assume that it requires everything.
|
||||
|
|
@ -514,15 +532,15 @@ func goModSummary(m module.Version) (*modFileSummary, error) {
|
|||
return summary, nil
|
||||
}
|
||||
|
||||
actual := resolveReplacement(m)
|
||||
if HasModRoot() && cfg.BuildMod == "readonly" && actual.Version != "" {
|
||||
actual, replacedFrom := resolveReplacement(m)
|
||||
if HasModRoot() && cfg.BuildMod == "readonly" && !inWorkspaceMode() && actual.Version != "" {
|
||||
key := module.Version{Path: actual.Path, Version: actual.Version + "/go.mod"}
|
||||
if !modfetch.HaveSum(key) {
|
||||
suggestion := fmt.Sprintf("; to add it:\n\tgo mod download %s", m.Path)
|
||||
return nil, module.VersionError(actual, &sumMissingError{suggestion: suggestion})
|
||||
}
|
||||
}
|
||||
summary, err := rawGoModSummary(actual)
|
||||
summary, err := rawGoModSummary(actual, replacedFrom)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -553,27 +571,29 @@ func goModSummary(m module.Version) (*modFileSummary, error) {
|
|||
}
|
||||
}
|
||||
|
||||
if index != nil && len(index.exclude) > 0 {
|
||||
// Drop any requirements on excluded versions.
|
||||
// Don't modify the cached summary though, since we might need the raw
|
||||
// summary separately.
|
||||
haveExcludedReqs := false
|
||||
for _, r := range summary.require {
|
||||
if index.exclude[r] {
|
||||
haveExcludedReqs = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if haveExcludedReqs {
|
||||
s := new(modFileSummary)
|
||||
*s = *summary
|
||||
s.require = make([]module.Version, 0, len(summary.require))
|
||||
for _, mainModule := range MainModules.Versions() {
|
||||
if index := MainModules.Index(mainModule); index != nil && len(index.exclude) > 0 {
|
||||
// Drop any requirements on excluded versions.
|
||||
// Don't modify the cached summary though, since we might need the raw
|
||||
// summary separately.
|
||||
haveExcludedReqs := false
|
||||
for _, r := range summary.require {
|
||||
if !index.exclude[r] {
|
||||
s.require = append(s.require, r)
|
||||
if index.exclude[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
|
||||
|
|
@ -584,18 +604,23 @@ func goModSummary(m module.Version) (*modFileSummary, error) {
|
|||
// its dependencies.
|
||||
//
|
||||
// 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")
|
||||
}
|
||||
|
||||
type key struct {
|
||||
m module.Version
|
||||
replacedFrom string
|
||||
}
|
||||
type cached struct {
|
||||
summary *modFileSummary
|
||||
err error
|
||||
}
|
||||
c := rawGoModSummaryCache.Do(m, func() interface{} {
|
||||
c := rawGoModSummaryCache.Do(key{m, replacedFrom}, func() interface{} {
|
||||
summary := new(modFileSummary)
|
||||
name, data, err := rawGoModData(m)
|
||||
name, data, err := rawGoModData(m, replacedFrom)
|
||||
if err != nil {
|
||||
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.
|
||||
// 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 == "" {
|
||||
// m is a replacement module with only a file path.
|
||||
dir := m.Path
|
||||
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")
|
||||
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,
|
||||
// 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 {
|
||||
latest module.Version
|
||||
err error
|
||||
latest module.Version
|
||||
replacedFrom string // if latest is a replacement
|
||||
err error
|
||||
}
|
||||
e := latestVersionIgnoringRetractionsCache.Do(path, func() interface{} {
|
||||
ctx, span := trace.StartSpan(ctx, "queryLatestVersionIgnoringRetractions "+path)
|
||||
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.
|
||||
// No need to query.
|
||||
return &entry{latest: repl}
|
||||
return &entry{latest: repl, replacedFrom: replFrom}
|
||||
}
|
||||
|
||||
// Find the latest version of the module.
|
||||
|
|
@ -709,12 +738,12 @@ func queryLatestVersionIgnoringRetractions(ctx context.Context, path string) (la
|
|||
return &entry{err: err}
|
||||
}
|
||||
latest := module.Version{Path: path, Version: rev.Version}
|
||||
if repl := resolveReplacement(latest); repl.Path != "" {
|
||||
latest = repl
|
||||
if repl, replFrom := resolveReplacement(latest); repl.Path != "" {
|
||||
latest, replacedFrom = repl, replFrom
|
||||
}
|
||||
return &entry{latest: latest}
|
||||
return &entry{latest: latest, replacedFrom: replacedFrom}
|
||||
}).(*entry)
|
||||
return e.latest, e.err
|
||||
return e.latest, e.replacedFrom, e.err
|
||||
}
|
||||
|
||||
var latestVersionIgnoringRetractionsCache par.Cache // path → queryLatestVersionIgnoringRetractions result
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ type mvsReqs struct {
|
|||
}
|
||||
|
||||
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
|
||||
// global build list.
|
||||
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) {
|
||||
// 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
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -110,11 +110,12 @@ func queryProxy(ctx context.Context, proxy, path, query, current string, allowed
|
|||
allowed = func(context.Context, module.Version) error { return nil }
|
||||
}
|
||||
|
||||
if path == Target.Path && (query == "upgrade" || query == "patch") {
|
||||
if err := allowed(ctx, Target); err != nil {
|
||||
if MainModules.Contains(path) && (query == "upgrade" || query == "patch") {
|
||||
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 &modfetch.RevInfo{Version: Target.Version}, nil
|
||||
return &modfetch.RevInfo{Version: m.Version}, nil
|
||||
}
|
||||
|
||||
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)
|
||||
|
||||
if len(pkgMods) == 0 && err == nil {
|
||||
replacement, _ := Replacement(modOnly.Mod)
|
||||
return nil, &PackageNotInModuleError{
|
||||
Mod: modOnly.Mod,
|
||||
Replacement: Replacement(modOnly.Mod),
|
||||
Replacement: replacement,
|
||||
Query: query,
|
||||
Pattern: pattern,
|
||||
}
|
||||
|
|
@ -551,7 +553,7 @@ func QueryPattern(ctx context.Context, pattern, query string, current func(strin
|
|||
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)
|
||||
|
||||
if i := strings.Index(pattern, "..."); i >= 0 {
|
||||
|
|
@ -559,30 +561,32 @@ func QueryPattern(ctx context.Context, pattern, query string, current func(strin
|
|||
if base == "." {
|
||||
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)
|
||||
matchPackages(ctx, m, imports.AnyTags(), omitStd, []module.Version{mod})
|
||||
return m
|
||||
}
|
||||
} 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)
|
||||
prefix := mod.Path
|
||||
if mod == Target {
|
||||
prefix = targetPrefix
|
||||
if MainModules.Contains(mod.Path) {
|
||||
prefix = MainModules.PathPrefix(module.Version{Path: mod.Path})
|
||||
}
|
||||
if _, ok, err := dirInModule(pattern, prefix, root, isLocal); err != nil {
|
||||
m.AddError(err)
|
||||
} else if ok {
|
||||
m.Pkgs = []string{pattern}
|
||||
for _, root := range roots {
|
||||
if _, ok, err := dirInModule(pattern, prefix, root, isLocal); err != nil {
|
||||
m.AddError(err)
|
||||
} else if ok {
|
||||
m.Pkgs = []string{pattern}
|
||||
}
|
||||
}
|
||||
return m
|
||||
}
|
||||
}
|
||||
|
||||
var queryMatchesMainModule bool
|
||||
if HasModRoot() {
|
||||
m := match(Target, modRoot, true)
|
||||
var mainModuleMatches []module.Version
|
||||
for _, mainModule := range MainModules.Versions() {
|
||||
m := match(mainModule, modRoots, true)
|
||||
if len(m.Pkgs) > 0 {
|
||||
if query != "upgrade" && query != "patch" {
|
||||
return nil, nil, &QueryMatchesPackagesInMainModuleError{
|
||||
|
|
@ -591,12 +595,12 @@ func QueryPattern(ctx context.Context, pattern, query string, current func(strin
|
|||
Packages: m.Pkgs,
|
||||
}
|
||||
}
|
||||
if err := allowed(ctx, Target); 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)
|
||||
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, mainModule.Path, err)
|
||||
}
|
||||
return []QueryResult{{
|
||||
Mod: Target,
|
||||
Rev: &modfetch.RevInfo{Version: Target.Version},
|
||||
Mod: mainModule,
|
||||
Rev: &modfetch.RevInfo{Version: mainModule.Version},
|
||||
Packages: m.Pkgs,
|
||||
}}, nil, nil
|
||||
}
|
||||
|
|
@ -604,15 +608,17 @@ func QueryPattern(ctx context.Context, pattern, query string, current func(strin
|
|||
return nil, nil, err
|
||||
}
|
||||
|
||||
if matchPattern(Target.Path) {
|
||||
queryMatchesMainModule = true
|
||||
var matchesMainModule bool
|
||||
if matchPattern(mainModule.Path) {
|
||||
mainModuleMatches = append(mainModuleMatches, mainModule)
|
||||
matchesMainModule = true
|
||||
}
|
||||
|
||||
if (query == "upgrade" || query == "patch") && queryMatchesMainModule {
|
||||
if err := allowed(ctx, Target); err == nil {
|
||||
if (query == "upgrade" || query == "patch") && matchesMainModule {
|
||||
if err := allowed(ctx, mainModule); err == nil {
|
||||
modOnly = &QueryResult{
|
||||
Mod: Target,
|
||||
Rev: &modfetch.RevInfo{Version: Target.Version},
|
||||
Mod: mainModule,
|
||||
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 modOnly != nil {
|
||||
return nil, modOnly, nil
|
||||
} else if queryMatchesMainModule {
|
||||
return nil, nil, &QueryMatchesMainModuleError{
|
||||
Pattern: pattern,
|
||||
Query: query,
|
||||
} else if len(mainModuleMatches) != 0 {
|
||||
return nil, nil, &QueryMatchesMainModulesError{
|
||||
MainModules: mainModuleMatches,
|
||||
Pattern: pattern,
|
||||
Query: query,
|
||||
}
|
||||
} else {
|
||||
return nil, nil, &PackageNotInModuleError{
|
||||
Mod: Target,
|
||||
Query: query,
|
||||
Pattern: pattern,
|
||||
MainModules: mainModuleMatches,
|
||||
Query: query,
|
||||
Pattern: pattern,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -656,15 +663,16 @@ func QueryPattern(ctx context.Context, pattern, query string, current func(strin
|
|||
if err != nil {
|
||||
return r, err
|
||||
}
|
||||
m := match(r.Mod, root, isLocal)
|
||||
m := match(r.Mod, []string{root}, isLocal)
|
||||
r.Packages = m.Pkgs
|
||||
if len(r.Packages) == 0 && !matchPattern(path) {
|
||||
if err := firstError(m); err != nil {
|
||||
return r, err
|
||||
}
|
||||
replacement, _ := Replacement(r.Mod)
|
||||
return r, &PackageNotInModuleError{
|
||||
Mod: r.Mod,
|
||||
Replacement: Replacement(r.Mod),
|
||||
Replacement: replacement,
|
||||
Query: query,
|
||||
Pattern: pattern,
|
||||
}
|
||||
|
|
@ -684,8 +692,8 @@ func QueryPattern(ctx context.Context, pattern, query string, current func(strin
|
|||
return err
|
||||
})
|
||||
|
||||
if queryMatchesMainModule && len(results) == 0 && modOnly == nil && errors.Is(err, fs.ErrNotExist) {
|
||||
return nil, nil, &QueryMatchesMainModuleError{
|
||||
if len(mainModuleMatches) > 0 && len(results) == 0 && modOnly == nil && errors.Is(err, fs.ErrNotExist) {
|
||||
return nil, nil, &QueryMatchesMainModulesError{
|
||||
Pattern: pattern,
|
||||
Query: query,
|
||||
}
|
||||
|
|
@ -701,8 +709,13 @@ func QueryPattern(ctx context.Context, pattern, query string, current func(strin
|
|||
func modulePrefixesExcludingTarget(path string) []string {
|
||||
prefixes := make([]string, 0, strings.Count(path, "/")+1)
|
||||
|
||||
mainModulePrefixes := make(map[string]bool)
|
||||
for _, m := range MainModules.Versions() {
|
||||
mainModulePrefixes[m.Path] = true
|
||||
}
|
||||
|
||||
for {
|
||||
if path != targetPrefix {
|
||||
if !mainModulePrefixes[path] {
|
||||
if _, _, ok := module.SplitPathVersion(path); ok {
|
||||
prefixes = append(prefixes, path)
|
||||
}
|
||||
|
|
@ -759,7 +772,7 @@ func queryPrefixModules(ctx context.Context, candidateModules []string, queryMod
|
|||
case *PackageNotInModuleError:
|
||||
// Given the option, prefer to attribute “package not in module”
|
||||
// to modules other than the main one.
|
||||
if noPackage == nil || noPackage.Mod == Target {
|
||||
if noPackage == nil || MainModules.Contains(noPackage.Mod.Path) {
|
||||
noPackage = rErr
|
||||
}
|
||||
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
|
||||
// to return a non-400 status code to suppress fallback.
|
||||
type PackageNotInModuleError struct {
|
||||
MainModules []module.Version
|
||||
Mod module.Version
|
||||
Replacement module.Version
|
||||
Query string
|
||||
|
|
@ -885,11 +899,15 @@ type PackageNotInModuleError struct {
|
|||
}
|
||||
|
||||
func (e *PackageNotInModuleError) Error() string {
|
||||
if e.Mod == Target {
|
||||
if strings.Contains(e.Pattern, "...") {
|
||||
return fmt.Sprintf("main module (%s) does not contain packages matching %s", Target.Path, e.Pattern)
|
||||
if len(e.MainModules) > 0 {
|
||||
prefix := "workspace modules do"
|
||||
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 := ""
|
||||
|
|
@ -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
|
||||
// and simpler.
|
||||
func versionHasGoMod(_ context.Context, m module.Version) (bool, error) {
|
||||
_, data, err := rawGoModData(m)
|
||||
_, data, err := rawGoModData(m, "")
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
|
@ -978,14 +996,18 @@ func lookupRepo(proxy, path string) (repo versionRepo, err error) {
|
|||
repo = emptyRepo{path: path, err: err}
|
||||
}
|
||||
|
||||
if index == nil {
|
||||
return repo, err
|
||||
}
|
||||
if _, ok := index.highestReplaced[path]; !ok {
|
||||
return repo, err
|
||||
// TODO(#45713): Join all the highestReplaced fields into a single value.
|
||||
for _, mm := range MainModules.Versions() {
|
||||
index := MainModules.Index(mm)
|
||||
if index == nil {
|
||||
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.
|
||||
|
|
@ -1024,11 +1046,13 @@ func (rr *replacementRepo) Versions(prefix string) ([]string, error) {
|
|||
}
|
||||
|
||||
versions := repoVersions
|
||||
if index != nil && len(index.replace) > 0 {
|
||||
path := rr.ModulePath()
|
||||
for m, _ := range index.replace {
|
||||
if m.Path == path && strings.HasPrefix(m.Version, prefix) && m.Version != "" && !module.IsPseudoVersion(m.Version) {
|
||||
versions = append(versions, m.Version)
|
||||
for _, mm := range MainModules.Versions() {
|
||||
if index := MainModules.Index(mm); index != nil && len(index.replace) > 0 {
|
||||
path := rr.ModulePath()
|
||||
for m, _ := range index.replace {
|
||||
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) {
|
||||
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
|
||||
}
|
||||
|
||||
|
|
@ -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 rr.replacementStat(v)
|
||||
|
|
@ -1073,27 +1106,42 @@ func (rr *replacementRepo) Stat(rev string) (*modfetch.RevInfo, error) {
|
|||
|
||||
func (rr *replacementRepo) Latest() (*modfetch.RevInfo, error) {
|
||||
info, err := rr.repo.Latest()
|
||||
path := rr.ModulePath()
|
||||
|
||||
if index != nil {
|
||||
path := rr.ModulePath()
|
||||
if v, ok := index.highestReplaced[path]; ok {
|
||||
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")
|
||||
highestReplaced, found := "", false
|
||||
for _, mm := range MainModules.Versions() {
|
||||
if index := MainModules.Index(mm); index != nil {
|
||||
if v, ok := index.highestReplaced[path]; ok {
|
||||
if !found {
|
||||
highestReplaced, found = v, true
|
||||
continue
|
||||
}
|
||||
if semver.Compare(v, highestReplaced) > 0 {
|
||||
highestReplaced = v
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if err != nil || semver.Compare(v, info.Version) > 0 {
|
||||
return rr.replacementStat(v)
|
||||
if found {
|
||||
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
|
||||
|
|
@ -1108,20 +1156,46 @@ func (rr *replacementRepo) replacementStat(v string) (*modfetch.RevInfo, error)
|
|||
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.
|
||||
// (The main module's version cannot be changed.)
|
||||
type QueryMatchesMainModuleError struct {
|
||||
Pattern string
|
||||
Query string
|
||||
type QueryMatchesMainModulesError struct {
|
||||
MainModules []module.Version
|
||||
Pattern string
|
||||
Query string
|
||||
}
|
||||
|
||||
func (e *QueryMatchesMainModuleError) Error() string {
|
||||
if e.Pattern == Target.Path {
|
||||
func (e *QueryMatchesMainModulesError) Error() string {
|
||||
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 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
|
||||
|
|
|
|||
|
|
@ -131,9 +131,10 @@ func matchPackages(ctx context.Context, m *search.Match, tags map[string]bool, f
|
|||
}
|
||||
|
||||
if cfg.BuildMod == "vendor" {
|
||||
if HasModRoot() {
|
||||
walkPkgs(ModRoot(), targetPrefix, pruneGoMod|pruneVendor)
|
||||
walkPkgs(filepath.Join(ModRoot(), "vendor"), "", pruneVendor)
|
||||
mod := MainModules.mustGetSingleMainModule()
|
||||
if modRoot := MainModules.ModRoot(mod); modRoot != "" {
|
||||
walkPkgs(modRoot, MainModules.PathPrefix(mod), pruneGoMod|pruneVendor)
|
||||
walkPkgs(filepath.Join(modRoot, "vendor"), "", pruneVendor)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
|
@ -147,12 +148,12 @@ func matchPackages(ctx context.Context, m *search.Match, tags map[string]bool, f
|
|||
root, modPrefix string
|
||||
isLocal bool
|
||||
)
|
||||
if mod == Target {
|
||||
if !HasModRoot() {
|
||||
if MainModules.Contains(mod.Path) {
|
||||
if MainModules.ModRoot(mod) == "" {
|
||||
continue // If there is no main module, we can't search in it.
|
||||
}
|
||||
root = ModRoot()
|
||||
modPrefix = targetPrefix
|
||||
root = MainModules.ModRoot(mod)
|
||||
modPrefix = MainModules.PathPrefix(mod)
|
||||
isLocal = true
|
||||
} else {
|
||||
var err error
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ import (
|
|||
|
||||
"cmd/go/internal/base"
|
||||
|
||||
"golang.org/x/mod/modfile"
|
||||
"golang.org/x/mod/module"
|
||||
"golang.org/x/mod/semver"
|
||||
)
|
||||
|
|
@ -35,13 +36,13 @@ type vendorMetadata struct {
|
|||
}
|
||||
|
||||
// readVendorList reads the list of vendored modules from vendor/modules.txt.
|
||||
func readVendorList() {
|
||||
func readVendorList(mainModule module.Version) {
|
||||
vendorOnce.Do(func() {
|
||||
vendorList = nil
|
||||
vendorPkgModule = make(map[string]module.Version)
|
||||
vendorVersion = make(map[string]string)
|
||||
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 !errors.Is(err, fs.ErrNotExist) {
|
||||
base.Fatalf("go: %s", err)
|
||||
|
|
@ -134,8 +135,8 @@ func readVendorList() {
|
|||
// 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
|
||||
// requirements and replacements listed in the main module's go.mod file.
|
||||
func checkVendorConsistency() {
|
||||
readVendorList()
|
||||
func checkVendorConsistency(index *modFileIndex, modFile *modfile.File) {
|
||||
readVendorList(MainModules.mustGetSingleMainModule())
|
||||
|
||||
pre114 := false
|
||||
if semver.Compare(index.goVersionV, "v1.14") < 0 {
|
||||
|
|
@ -208,7 +209,7 @@ func checkVendorConsistency() {
|
|||
}
|
||||
|
||||
for _, mod := range vendorReplaced {
|
||||
r := Replacement(mod)
|
||||
r, _ := Replacement(mod)
|
||||
if r == (module.Version{}) {
|
||||
vendErrorf(mod, "is marked as replaced in vendor/modules.txt, but not replaced in go.mod")
|
||||
continue
|
||||
|
|
@ -219,6 +220,7 @@ func checkVendorConsistency() {
|
|||
}
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ package mvs
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"sort"
|
||||
"sync"
|
||||
|
||||
|
|
@ -85,11 +86,11 @@ type DowngradeReqs interface {
|
|||
// of the list are sorted by path.
|
||||
//
|
||||
// See https://research.swtch.com/vgo-mvs for details.
|
||||
func BuildList(target module.Version, reqs Reqs) ([]module.Version, error) {
|
||||
return buildList(target, reqs, nil)
|
||||
func BuildList(targets []module.Version, reqs Reqs) ([]module.Version, error) {
|
||||
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 {
|
||||
if reqs.Max(v1, v2) != v1 {
|
||||
return -1
|
||||
|
|
@ -102,7 +103,7 @@ func buildList(target module.Version, reqs Reqs, upgrade func(module.Version) (m
|
|||
|
||||
var (
|
||||
mu sync.Mutex
|
||||
g = NewGraph(cmp, []module.Version{target})
|
||||
g = NewGraph(cmp, targets)
|
||||
upgrades = map[module.Version]module.Version{}
|
||||
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
|
||||
// does high-latency network operations.
|
||||
var work par.Work
|
||||
work.Add(target)
|
||||
for _, target := range targets {
|
||||
work.Add(target)
|
||||
}
|
||||
work.Do(10, func(item interface{}) {
|
||||
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.
|
||||
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.
|
||||
// "" denotes the main module, which has no version. However, MVS treats
|
||||
// version strings as opaque, so "" is not a special value here.
|
||||
// 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
|
||||
}
|
||||
|
|
@ -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,
|
||||
// with the constraint that all module paths listed in base must
|
||||
// appear in the returned list.
|
||||
func Req(target module.Version, base []string, reqs Reqs) ([]module.Version, error) {
|
||||
list, err := BuildList(target, reqs)
|
||||
func Req(mainModule module.Version, base []string, reqs Reqs) ([]module.Version, error) {
|
||||
list, err := BuildList([]module.Version{mainModule}, reqs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -194,7 +197,8 @@ func Req(target module.Version, base []string, reqs Reqs) ([]module.Version, err
|
|||
// Compute postorder, cache requirements.
|
||||
var postorder []module.Version
|
||||
reqCache := map[module.Version][]module.Version{}
|
||||
reqCache[target] = nil
|
||||
reqCache[mainModule] = nil
|
||||
|
||||
var walk func(module.Version) error
|
||||
walk = func(m module.Version) error {
|
||||
_, 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
|
||||
// in which every module is upgraded to its latest version.
|
||||
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 {
|
||||
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 {
|
||||
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
|
||||
// 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 {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -446,7 +450,7 @@ List:
|
|||
// list with the actual versions of the downgraded modules as selected by MVS,
|
||||
// instead of our initial downgrades.
|
||||
// (See the downhiddenartifact and downhiddencross test cases).
|
||||
actual, err := BuildList(target, &override{
|
||||
actual, err := BuildList([]module.Version{target}, &override{
|
||||
target: target,
|
||||
list: downgraded,
|
||||
Reqs: reqs,
|
||||
|
|
@ -466,7 +470,7 @@ List:
|
|||
}
|
||||
}
|
||||
|
||||
return BuildList(target, &override{
|
||||
return BuildList([]module.Version{target}, &override{
|
||||
target: target,
|
||||
list: downgraded,
|
||||
Reqs: reqs,
|
||||
|
|
|
|||
|
|
@ -507,7 +507,7 @@ func Test(t *testing.T) {
|
|||
t.Fatalf("build takes one argument: %q", line)
|
||||
}
|
||||
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)
|
||||
})
|
||||
continue
|
||||
|
|
|
|||
|
|
@ -65,6 +65,7 @@ func init() {
|
|||
CmdRun.Run = runRun // break init loop
|
||||
|
||||
work.AddBuildFlags(CmdRun, work.DefaultBuildFlags)
|
||||
base.AddWorkfileFlag(&CmdRun.Flag)
|
||||
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) {
|
||||
modload.InitWorkfile()
|
||||
|
||||
if shouldUseOutsideModuleMode(args) {
|
||||
// Set global module flags for 'go run cmd@version'.
|
||||
// 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
|
||||
// potentially match a local pattern. The pattern must begin with an absolute
|
||||
// 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,
|
||||
// MatchDirs appends those errors to m.Errs.
|
||||
func (m *Match) MatchDirs() {
|
||||
func (m *Match) MatchDirs(modRoots []string) {
|
||||
m.Dirs = []string{}
|
||||
if !m.IsLocal() {
|
||||
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
|
||||
// and in the returned import paths.
|
||||
|
||||
if modRoot != "" {
|
||||
if len(modRoots) > 1 {
|
||||
abs, err := filepath.Abs(dir)
|
||||
if err != nil {
|
||||
m.AddError(err)
|
||||
return
|
||||
}
|
||||
if !hasFilepathPrefix(abs, modRoot) {
|
||||
m.AddError(fmt.Errorf("directory %s is outside module root (%s)", abs, modRoot))
|
||||
return
|
||||
var found bool
|
||||
for _, modRoot := range modRoots {
|
||||
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.
|
||||
// It calls ImportPathsQuiet and then WarnUnmatched.
|
||||
func ImportPaths(patterns []string) []*Match {
|
||||
matches := ImportPathsQuiet(patterns)
|
||||
func ImportPaths(patterns, modRoots []string) []*Match {
|
||||
matches := ImportPathsQuiet(patterns, modRoots)
|
||||
WarnUnmatched(matches)
|
||||
return 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
|
||||
for _, a := range CleanPatterns(patterns) {
|
||||
m := NewMatch(a)
|
||||
if m.IsLocal() {
|
||||
m.MatchDirs()
|
||||
m.MatchDirs(modRoots)
|
||||
|
||||
// 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
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ import (
|
|||
"cmd/go/internal/cfg"
|
||||
"cmd/go/internal/load"
|
||||
"cmd/go/internal/lockedfile"
|
||||
"cmd/go/internal/modload"
|
||||
"cmd/go/internal/search"
|
||||
"cmd/go/internal/trace"
|
||||
"cmd/go/internal/work"
|
||||
|
|
@ -582,6 +583,7 @@ var defaultVetFlags = []string{
|
|||
}
|
||||
|
||||
func runTest(ctx context.Context, cmd *base.Command, args []string) {
|
||||
modload.InitWorkfile()
|
||||
pkgArgs, testArgs = testFlags(args)
|
||||
|
||||
if cfg.DebugTrace != "" {
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ import (
|
|||
|
||||
func init() {
|
||||
work.AddBuildFlags(CmdTest, work.OmitVFlag)
|
||||
base.AddWorkfileFlag(&CmdTest.Flag)
|
||||
|
||||
cf := CmdTest.Flag
|
||||
cf.BoolVar(&testC, "c", false, "")
|
||||
|
|
|
|||
|
|
@ -121,6 +121,14 @@ and test commands:
|
|||
directory, but it is not accessed. When -modfile is specified, an
|
||||
alternate go.sum file is also used: its path is derived from the
|
||||
-modfile flag by trimming the ".mod" extension and appending ".sum".
|
||||
-workfile file
|
||||
in module aware mode, use the given go.work file as a workspace file.
|
||||
By default or when -workfile is "auto", the go command searches for a
|
||||
file named go.work in the current directory and then containing directories
|
||||
until one is found. If a valid go.work file is found, the modules
|
||||
specified will collectively be used as the main modules. If -workfile
|
||||
is "off", or a go.work file is not found in "auto" mode, workspace
|
||||
mode is disabled.
|
||||
-overlay file
|
||||
read a JSON config file that provides an overlay for build operations.
|
||||
The file is a JSON struct with a single field, named 'Replace', that
|
||||
|
|
@ -201,6 +209,7 @@ func init() {
|
|||
|
||||
AddBuildFlags(CmdBuild, DefaultBuildFlags)
|
||||
AddBuildFlags(CmdInstall, DefaultBuildFlags)
|
||||
base.AddWorkfileFlag(&CmdBuild.Flag)
|
||||
}
|
||||
|
||||
// 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()
|
||||
|
||||
func runBuild(ctx context.Context, cmd *base.Command, args []string) {
|
||||
modload.InitWorkfile()
|
||||
BuildInit()
|
||||
var b Builder
|
||||
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.
|
||||
go run ./stdonly/stdonly.go
|
||||
stdout 'path is command-line-arguments$'
|
||||
stdout 'main is command-line-arguments \(devel\)'
|
||||
stdout 'main is $'
|
||||
|
||||
# 'go generate' should work with file arguments.
|
||||
[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
|
||||
|
||||
|
||||
# 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.
|
||||
cp go.alt.mod 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 '^\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.
|
||||
[!buildmode:pie] stop
|
||||
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":
|
||||
arrow := 2
|
||||
if len(args) >= 2 && args[1] == "=>" {
|
||||
arrow = 1
|
||||
}
|
||||
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)
|
||||
replace, wrappederr := parseReplace(f.Syntax.Name, line, verb, args, fix)
|
||||
if wrappederr != nil {
|
||||
*errs = append(*errs, *wrappederr)
|
||||
return
|
||||
}
|
||||
s, err := parseString(&args[0])
|
||||
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,
|
||||
})
|
||||
f.Replace = append(f.Replace, replace)
|
||||
|
||||
case "retract":
|
||||
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
|
||||
// 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
|
||||
// as a directory path. Just like on the go command line, relative 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 {
|
||||
return addReplace(f.Syntax, &f.Replace, oldPath, oldVers, newPath, newVers)
|
||||
}
|
||||
|
||||
func addReplace(syntax *FileSyntax, replace *[]*Replace, oldPath, oldVers, newPath, newVers string) error {
|
||||
need := true
|
||||
old := module.Version{Path: oldPath, Version: oldVers}
|
||||
new := module.Version{Path: newPath, Version: newVers}
|
||||
|
|
@ -1178,12 +1260,12 @@ func (f *File) AddReplace(oldPath, oldVers, newPath, newVers string) error {
|
|||
}
|
||||
|
||||
var hint *Line
|
||||
for _, r := range f.Replace {
|
||||
for _, r := range *replace {
|
||||
if r.Old.Path == oldPath && (oldVers == "" || r.Old.Version == oldVers) {
|
||||
if need {
|
||||
// Found replacement for old; update to use new.
|
||||
r.New = new
|
||||
f.Syntax.updateLine(r.Syntax, tokens...)
|
||||
syntax.updateLine(r.Syntax, tokens...)
|
||||
need = false
|
||||
continue
|
||||
}
|
||||
|
|
@ -1196,7 +1278,7 @@ func (f *File) AddReplace(oldPath, oldVers, newPath, newVers string) error {
|
|||
}
|
||||
}
|
||||
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
|
||||
}
|
||||
|
|
@ -1282,30 +1364,36 @@ func (f *File) SortBlocks() {
|
|||
// retract directives are not de-duplicated since comments are
|
||||
// meaningful, and versions may be retracted multiple times.
|
||||
func (f *File) removeDups() {
|
||||
removeDups(f.Syntax, &f.Exclude, &f.Replace)
|
||||
}
|
||||
|
||||
func removeDups(syntax *FileSyntax, exclude *[]*Exclude, replace *[]*Replace) {
|
||||
kill := make(map[*Line]bool)
|
||||
|
||||
// Remove duplicate excludes.
|
||||
haveExclude := make(map[module.Version]bool)
|
||||
for _, x := range f.Exclude {
|
||||
if haveExclude[x.Mod] {
|
||||
kill[x.Syntax] = true
|
||||
continue
|
||||
if exclude != nil {
|
||||
haveExclude := make(map[module.Version]bool)
|
||||
for _, x := range *exclude {
|
||||
if haveExclude[x.Mod] {
|
||||
kill[x.Syntax] = true
|
||||
continue
|
||||
}
|
||||
haveExclude[x.Mod] = true
|
||||
}
|
||||
haveExclude[x.Mod] = true
|
||||
}
|
||||
var excl []*Exclude
|
||||
for _, x := range f.Exclude {
|
||||
if !kill[x.Syntax] {
|
||||
excl = append(excl, x)
|
||||
var excl []*Exclude
|
||||
for _, x := range *exclude {
|
||||
if !kill[x.Syntax] {
|
||||
excl = append(excl, x)
|
||||
}
|
||||
}
|
||||
*exclude = excl
|
||||
}
|
||||
f.Exclude = excl
|
||||
|
||||
// Remove duplicate replacements.
|
||||
// Later replacements take priority over earlier ones.
|
||||
haveReplace := make(map[module.Version]bool)
|
||||
for i := len(f.Replace) - 1; i >= 0; i-- {
|
||||
x := f.Replace[i]
|
||||
for i := len(*replace) - 1; i >= 0; i-- {
|
||||
x := (*replace)[i]
|
||||
if haveReplace[x.Old] {
|
||||
kill[x.Syntax] = true
|
||||
continue
|
||||
|
|
@ -1313,18 +1401,18 @@ func (f *File) removeDups() {
|
|||
haveReplace[x.Old] = true
|
||||
}
|
||||
var repl []*Replace
|
||||
for _, x := range f.Replace {
|
||||
for _, x := range *replace {
|
||||
if !kill[x.Syntax] {
|
||||
repl = append(repl, x)
|
||||
}
|
||||
}
|
||||
f.Replace = repl
|
||||
*replace = repl
|
||||
|
||||
// Duplicate require and retract directives are not removed.
|
||||
|
||||
// Drop killed statements from the syntax tree.
|
||||
var stmts []Expr
|
||||
for _, stmt := range f.Syntax.Stmt {
|
||||
for _, stmt := range syntax.Stmt {
|
||||
switch stmt := stmt.(type) {
|
||||
case *Line:
|
||||
if kill[stmt] {
|
||||
|
|
@ -1344,7 +1432,7 @@ func (f *File) removeDups() {
|
|||
}
|
||||
stmts = append(stmts, stmt)
|
||||
}
|
||||
f.Syntax.Stmt = stmts
|
||||
syntax.Stmt = stmts
|
||||
}
|
||||
|
||||
// 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
|
||||
golang.org/x/crypto/ed25519
|
||||
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
|
||||
golang.org/x/mod/internal/lazyregexp
|
||||
golang.org/x/mod/modfile
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue