1
0
mirror of https://github.com/golang/go synced 2024-11-23 19:40:08 -07:00

cmd/go: add -retracted flag to 'go list'

The -retracted flag causes 'go list' to load information about
retracted module module versions.

When -retracted is used with -f or -json, the Retracted field is set
to a string containing the reason for the retraction on retracted
module versions. The string is based on comments on the retract
directive. This field is also populated when the -u flag is used.

When -retracted is used with -versions, retracted versions are shown.
Normally, they are omitted.

For #24031

Change-Id: Ic13d516eddffb1b8404e21034f78cecc9896d1b8
Reviewed-on: https://go-review.googlesource.com/c/go/+/228382
Reviewed-by: Michael Matloob <matloob@golang.org>
Reviewed-by: Bryan C. Mills <bcmills@google.com>
This commit is contained in:
Jay Conrod 2020-04-15 14:42:15 -04:00
parent 0bbd386e8b
commit eb3e27ac1a
18 changed files with 455 additions and 52 deletions

View File

@ -916,6 +916,7 @@
// Dir string // directory holding files for this module, if any
// GoMod string // path to go.mod file used when loading this module, if any
// GoVersion string // go version used in module
// Retracted string // retraction information, if any (with -retracted or -u)
// Error *ModuleError // error loading module
// }
//
@ -947,14 +948,16 @@
// The -u flag adds information about available upgrades.
// When the latest version of a given module is newer than
// the current one, list -u sets the Module's Update field
// to information about the newer module.
// to information about the newer module. list -u will also set
// the module's Retracted field if the current version is retracted.
// The Module's String method indicates an available upgrade by
// formatting the newer version in brackets after the current version.
// If a version is retracted, the string "(retracted)" will follow it.
// For example, 'go list -m -u all' might print:
//
// my/main/module
// golang.org/x/text v0.3.0 [v0.4.0] => /tmp/text
// rsc.io/pdf v0.1.1 [v0.1.2]
// rsc.io/pdf v0.1.1 (retracted) [v0.1.2]
//
// (For tools, 'go list -m -u -json all' may be more convenient to parse.)
//
@ -964,6 +967,14 @@
// the default output format to display the module path followed by the
// space-separated version list.
//
// The -retracted flag causes list to report information about retracted
// module versions. When -retracted is used with -f or -json, the Retracted
// field will be set to a string explaining why the version was retracted.
// The string is taken from comments on the retract directive in the
// module's go.mod file. When -retracted is used with -versions, retracted
// versions are listed together with unretracted versions. The -retracted
// flag may be used with or without -m.
//
// The arguments to list -m are interpreted as a list of modules, not packages.
// The main module is the module containing the current directory.
// The active modules are the main module and its dependencies.

View File

@ -10,6 +10,7 @@ import (
"bytes"
"context"
"encoding/json"
"fmt"
"io"
"os"
"sort"
@ -215,6 +216,7 @@ applied to a Go struct, but now a Module struct:
Dir string // directory holding files for this module, if any
GoMod string // path to go.mod file used when loading this module, if any
GoVersion string // go version used in module
Retracted string // retraction information, if any (with -retracted or -u)
Error *ModuleError // error loading module
}
@ -246,14 +248,16 @@ the replaced source code.)
The -u flag adds information about available upgrades.
When the latest version of a given module is newer than
the current one, list -u sets the Module's Update field
to information about the newer module.
to information about the newer module. list -u will also set
the module's Retracted field if the current version is retracted.
The Module's String method indicates an available upgrade by
formatting the newer version in brackets after the current version.
If a version is retracted, the string "(retracted)" will follow it.
For example, 'go list -m -u all' might print:
my/main/module
golang.org/x/text v0.3.0 [v0.4.0] => /tmp/text
rsc.io/pdf v0.1.1 [v0.1.2]
rsc.io/pdf v0.1.1 (retracted) [v0.1.2]
(For tools, 'go list -m -u -json all' may be more convenient to parse.)
@ -263,6 +267,14 @@ to semantic versioning, earliest to latest. The flag also changes
the default output format to display the module path followed by the
space-separated version list.
The -retracted flag causes list to report information about retracted
module versions. When -retracted is used with -f or -json, the Retracted
field will be set to a string explaining why the version was retracted.
The string is taken from comments on the retract directive in the
module's go.mod file. When -retracted is used with -versions, retracted
versions are listed together with unretracted versions. The -retracted
flag may be used with or without -m.
The arguments to list -m are interpreted as a list of modules, not packages.
The main module is the module containing the current directory.
The active modules are the main module and its dependencies.
@ -296,17 +308,18 @@ func init() {
}
var (
listCompiled = CmdList.Flag.Bool("compiled", false, "")
listDeps = CmdList.Flag.Bool("deps", false, "")
listE = CmdList.Flag.Bool("e", false, "")
listExport = CmdList.Flag.Bool("export", false, "")
listFmt = CmdList.Flag.String("f", "", "")
listFind = CmdList.Flag.Bool("find", false, "")
listJson = CmdList.Flag.Bool("json", false, "")
listM = CmdList.Flag.Bool("m", false, "")
listU = CmdList.Flag.Bool("u", false, "")
listTest = CmdList.Flag.Bool("test", false, "")
listVersions = CmdList.Flag.Bool("versions", false, "")
listCompiled = CmdList.Flag.Bool("compiled", false, "")
listDeps = CmdList.Flag.Bool("deps", false, "")
listE = CmdList.Flag.Bool("e", false, "")
listExport = CmdList.Flag.Bool("export", false, "")
listFmt = CmdList.Flag.String("f", "", "")
listFind = CmdList.Flag.Bool("find", false, "")
listJson = CmdList.Flag.Bool("json", false, "")
listM = CmdList.Flag.Bool("m", false, "")
listRetracted = CmdList.Flag.Bool("retracted", false, "")
listTest = CmdList.Flag.Bool("test", false, "")
listU = CmdList.Flag.Bool("u", false, "")
listVersions = CmdList.Flag.Bool("versions", false, "")
)
var nl = []byte{'\n'}
@ -367,6 +380,16 @@ func runList(ctx context.Context, cmd *base.Command, args []string) {
}
}
modload.Init()
if *listRetracted {
if cfg.BuildMod == "vendor" {
base.Fatalf("go list -retracted cannot be used when vendoring is enabled")
}
if !modload.Enabled() {
base.Fatalf("go list -retracted can only be used in module-aware mode")
}
}
if *listM {
// Module mode.
if *listCompiled {
@ -416,7 +439,7 @@ func runList(ctx context.Context, cmd *base.Command, args []string) {
modload.LoadBuildList(ctx)
mods := modload.ListModules(ctx, args, *listU, *listVersions)
mods := modload.ListModules(ctx, args, *listU, *listVersions, *listRetracted)
if !*listE {
for _, m := range mods {
if m.Error != nil {
@ -607,6 +630,55 @@ func runList(ctx context.Context, cmd *base.Command, args []string) {
}
}
// TODO(golang.org/issue/40676): This mechanism could be extended to support
// -u without -m.
if *listRetracted {
// Load retractions for modules that provide packages that will be printed.
// TODO(golang.org/issue/40775): Packages from the same module refer to
// distinct ModulePublic instance. It would be nice if they could all point
// to the same instance. This would require additional global state in
// modload.loaded, so that should be refactored first. For now, we update
// all instances.
modToArg := make(map[*modinfo.ModulePublic]string)
argToMods := make(map[string][]*modinfo.ModulePublic)
var args []string
addModule := func(mod *modinfo.ModulePublic) {
if mod.Version == "" {
return
}
arg := fmt.Sprintf("%s@%s", mod.Path, mod.Version)
if argToMods[arg] == nil {
args = append(args, arg)
}
argToMods[arg] = append(argToMods[arg], mod)
modToArg[mod] = arg
}
for _, p := range pkgs {
if p.Module == nil {
continue
}
addModule(p.Module)
if p.Module.Replace != nil {
addModule(p.Module.Replace)
}
}
if len(args) > 0 {
listU := false
listVersions := false
rmods := modload.ListModules(ctx, args, listU, listVersions, *listRetracted)
for i, arg := range args {
rmod := rmods[i]
for _, mod := range argToMods[arg] {
mod.Retracted = rmod.Retracted
if rmod.Error != nil && mod.Error == nil {
mod.Error = rmod.Error
}
}
}
}
}
// Record non-identity import mappings in p.ImportMap.
for _, p := range pkgs {
for i, srcPath := range p.Internal.RawImports {

View File

@ -12,8 +12,8 @@ import (
"cmd/go/internal/base"
"cmd/go/internal/cfg"
"cmd/go/internal/modload"
"cmd/go/internal/modfetch"
"cmd/go/internal/modload"
"cmd/go/internal/work"
"golang.org/x/mod/module"
@ -136,9 +136,10 @@ func runDownload(ctx context.Context, cmd *base.Command, args []string) {
var mods []*moduleJSON
listU := false
listVersions := false
listRetractions := false
type token struct{}
sem := make(chan token, runtime.GOMAXPROCS(0))
for _, info := range modload.ListModules(ctx, args, listU, listVersions) {
for _, info := range modload.ListModules(ctx, args, listU, listVersions, listRetractions) {
if info.Replace != nil {
info = info.Replace
}

View File

@ -69,12 +69,13 @@ func runWhy(ctx context.Context, cmd *base.Command, args []string) {
if *whyM {
listU := false
listVersions := false
listRetractions := false
for _, arg := range args {
if strings.Contains(arg, "@") {
base.Fatalf("go mod why: module query not allowed")
}
}
mods := modload.ListModules(ctx, args, listU, listVersions)
mods := modload.ListModules(ctx, args, listU, listVersions, listRetractions)
byModule := make(map[module.Version][]string)
for _, path := range loadALL(ctx) {
m := modload.PackageModule(path)

View File

@ -8,6 +8,7 @@ import (
"bytes"
"context"
"encoding/hex"
"errors"
"fmt"
"internal/goroot"
"os"
@ -58,7 +59,9 @@ func PackageModuleInfo(pkgpath string) *modinfo.ModulePublic {
if !ok {
return nil
}
return moduleInfo(context.TODO(), m, true)
fromBuildList := true
listRetracted := false
return moduleInfo(context.TODO(), m, fromBuildList, listRetracted)
}
func ModuleInfo(ctx context.Context, path string) *modinfo.ModulePublic {
@ -66,13 +69,17 @@ func ModuleInfo(ctx context.Context, path string) *modinfo.ModulePublic {
return nil
}
listRetracted := false
if i := strings.Index(path, "@"); i >= 0 {
return moduleInfo(ctx, module.Version{Path: path[:i], Version: path[i+1:]}, false)
m := module.Version{Path: path[:i], Version: path[i+1:]}
fromBuildList := false
return moduleInfo(ctx, m, fromBuildList, listRetracted)
}
for _, m := range BuildList() {
if m.Path == path {
return moduleInfo(ctx, m, true)
fromBuildList := true
return moduleInfo(ctx, m, fromBuildList, listRetracted)
}
}
@ -100,11 +107,37 @@ func addUpdate(ctx context.Context, m *modinfo.ModulePublic) {
}
// addVersions fills in m.Versions with the list of known versions.
func addVersions(ctx context.Context, m *modinfo.ModulePublic) {
m.Versions, _ = versions(ctx, m.Path, CheckAllowed)
// Excluded versions will be omitted. If listRetracted is false, retracted
// versions will also be omitted.
func addVersions(ctx context.Context, m *modinfo.ModulePublic, listRetracted bool) {
allowed := CheckAllowed
if listRetracted {
allowed = CheckExclusions
}
m.Versions, _ = versions(ctx, m.Path, allowed)
}
func moduleInfo(ctx context.Context, m module.Version, fromBuildList bool) *modinfo.ModulePublic {
// addRetraction fills in m.Retracted if the module was retracted by its author.
// m.Error is set if there's an error loading retraction information.
func addRetraction(ctx context.Context, m *modinfo.ModulePublic) {
if m.Version == "" {
return
}
err := checkRetractions(ctx, module.Version{Path: m.Path, Version: m.Version})
var rerr *retractedError
if errors.As(err, &rerr) {
if len(rerr.rationale) == 0 {
m.Retracted = []string{"retracted by module author"}
} else {
m.Retracted = rerr.rationale
}
} else if err != nil && m.Error == nil {
m.Error = &modinfo.ModuleError{Err: err.Error()}
}
}
func moduleInfo(ctx context.Context, m module.Version, fromBuildList, listRetracted bool) *modinfo.ModulePublic {
if m == Target {
info := &modinfo.ModulePublic{
Path: m.Path,
@ -152,6 +185,10 @@ func moduleInfo(ctx context.Context, m module.Version, fromBuildList bool) *modi
if err == nil {
m.Dir = dir
}
if listRetracted {
addRetraction(ctx, m)
}
}
if m.GoVersion == "" {
@ -205,6 +242,7 @@ func moduleInfo(ctx context.Context, m module.Version, fromBuildList bool) *modi
completeFromModCache(info.Replace)
info.Dir = info.Replace.Dir
info.GoMod = info.Replace.GoMod
info.Retracted = info.Replace.Retracted
}
info.GoVersion = info.Replace.GoVersion
return info

View File

@ -20,12 +20,12 @@ import (
"golang.org/x/mod/module"
)
func ListModules(ctx context.Context, args []string, listU, listVersions bool) []*modinfo.ModulePublic {
mods := listModules(ctx, args, listVersions)
func ListModules(ctx context.Context, args []string, listU, listVersions, listRetracted bool) []*modinfo.ModulePublic {
mods := listModules(ctx, args, listVersions, listRetracted)
type token struct{}
sem := make(chan token, runtime.GOMAXPROCS(0))
if listU || listVersions {
if listU || listVersions || listRetracted {
for _, m := range mods {
add := func(m *modinfo.ModulePublic) {
sem <- token{}
@ -34,7 +34,10 @@ func ListModules(ctx context.Context, args []string, listU, listVersions bool) [
addUpdate(ctx, m)
}
if listVersions {
addVersions(ctx, m)
addVersions(ctx, m, listRetracted)
}
if listRetracted || listU {
addRetraction(ctx, m)
}
<-sem
}()
@ -54,10 +57,10 @@ func ListModules(ctx context.Context, args []string, listU, listVersions bool) [
return mods
}
func listModules(ctx context.Context, args []string, listVersions bool) []*modinfo.ModulePublic {
func listModules(ctx context.Context, args []string, listVersions, listRetracted bool) []*modinfo.ModulePublic {
LoadBuildList(ctx)
if len(args) == 0 {
return []*modinfo.ModulePublic{moduleInfo(ctx, buildList[0], true)}
return []*modinfo.ModulePublic{moduleInfo(ctx, buildList[0], true, listRetracted)}
}
var mods []*modinfo.ModulePublic
@ -84,9 +87,9 @@ func listModules(ctx context.Context, args []string, listVersions bool) []*modin
}
allowed := CheckAllowed
if IsRevisionQuery(vers) {
if IsRevisionQuery(vers) || listRetracted {
// Allow excluded and retracted versions if the user asked for a
// specific revision.
// specific revision or used 'go list -retracted'.
allowed = nil
}
info, err := Query(ctx, path, vers, current, allowed)
@ -98,7 +101,8 @@ func listModules(ctx context.Context, args []string, listVersions bool) []*modin
})
continue
}
mods = append(mods, moduleInfo(ctx, module.Version{Path: path, Version: info.Version}, false))
mod := moduleInfo(ctx, module.Version{Path: path, Version: info.Version}, false, listRetracted)
mods = append(mods, mod)
continue
}
@ -123,7 +127,7 @@ func listModules(ctx context.Context, args []string, listVersions bool) []*modin
matched = true
if !matchedBuildList[i] {
matchedBuildList[i] = true
mods = append(mods, moduleInfo(ctx, m, true))
mods = append(mods, moduleInfo(ctx, m, true, listRetracted))
}
}
}
@ -135,7 +139,8 @@ func listModules(ctx context.Context, args []string, listVersions bool) []*modin
// Instead, resolve the module, even if it isn't an existing dependency.
info, err := Query(ctx, arg, "latest", "", nil)
if err == nil {
mods = append(mods, moduleInfo(ctx, module.Version{Path: arg, Version: info.Version}, false))
mod := moduleInfo(ctx, module.Version{Path: arg, Version: info.Version}, false, listRetracted)
mods = append(mods, mod)
} else {
mods = append(mods, &modinfo.ModulePublic{
Path: arg,

View File

@ -0,0 +1,8 @@
This version should be retracted, but the go.mod file for the version that would
contain the retraction is not available.
-- .mod --
module example.com/retract/missingmod
go 1.14
-- .info --
{"Version":"v1.0.0"}

View File

@ -0,0 +1,4 @@
The go.mod file at this version will be loaded to check for retractions
of earlier versions. However, the .mod file is not available.
-- .info --
{"Version":"v1.9.0"}

View File

@ -0,0 +1,14 @@
Module example.com/retract/self/prev is a module that retracts its own
latest version.
No unretracted versions are available.
-- .mod --
module example.com/retract/self/all
go 1.15
retract v1.9.0 // bad
-- .info --
{"Version":"v1.9.0"}

View File

@ -0,0 +1,16 @@
Module example.com/retract/self/prerelease is a module that retracts its own
latest version and all other release version.
A pre-release version higher than the highest release version is still
available, and that should be matched by @latest.
-- .mod --
module example.com/retract/self/prerelease
go 1.15
-- .info --
{"Version":"v1.0.0"}
-- p.go --
package p

View File

@ -0,0 +1,19 @@
Module example.com/retract/self/prerelease is a module that retracts its own
latest version and all other release version.
A pre-release version higher than the highest release version is still
available, and that should be matched by @latest.
-- .mod --
module example.com/retract/self/prerelease
go 1.15
retract v1.0.0 // bad
retract v1.9.0 // self
-- .info --
{"Version":"v1.9.0"}
-- p.go --
package p

View File

@ -0,0 +1,16 @@
Module example.com/retract/self/prerelease is a module that retracts its own
latest version and all other release version.
A pre-release version higher than the highest release version is still
available, and that should be matched by @latest.
-- .mod --
module example.com/retract/self/prerelease
go 1.15
-- .info --
{"Version":"v1.9.1-pre"}
-- p.go --
package p

View File

@ -0,0 +1,20 @@
See example.com_retract_self_pseudo_v1.9.0.txt.
This version is not retracted. It should be returned by the proxy's
@latest endpoint. It should match the @latest version query.
TODO(golang.org/issue/24031): the proxy and proxy.golang.org both return
the highest release version from the @latest endpoint, even if that
version is retracted, so there is no way for the go command to
discover an unretracted pseudo-version.
-- .mod --
module example.com/retract/self/pseudo
go 1.15
-- .info --
{"Version":"v0.0.0-20200325131415-01234567890ab"}
-- p.go --
package p

View File

@ -0,0 +1,14 @@
See example.com_retract_self_pseudo_v1.9.0.txt.
This version is retracted.
-- .mod --
module example.com/retract/self/pseudo
go 1.15
-- .info --
{"Version":"v1.0.0-bad"}
-- p.go --
package p

View File

@ -0,0 +1,16 @@
Module example.com/retract/self/pseudo is a module that retracts its own
latest version, as well as an earlier version.
An unretracted pseudo-version is available.
-- .mod --
module example.com/retract/self/pseudo
go 1.15
retract v1.0.0-bad // bad
retract v1.9.0 // self
-- .info --
{"Version":"v1.9.0"}

View File

@ -10,30 +10,25 @@ go mod download github.com/dmitshur-test/modtest5@v0.5.0-alpha
go mod download github.com/dmitshur-test/modtest5@v0.5.0-alpha.0.20190619023908-3da23a9deb9e
cmp $GOPATH/pkg/mod/cache/download/github.com/dmitshur-test/modtest5/@v/list $WORK/modtest5.list
env GOSUMDB=off # don't verify go.mod files when loading retractions
env GOPROXY=file:///$GOPATH/pkg/mod/cache/download
env GOPATH=$WORK/gopath2
mkdir $GOPATH
go list -m -json github.com/dmitshur-test/modtest5@latest
cmp stdout $WORK/modtest5.json
go list -m -f '{{.Path}} {{.Version}} {{.Time.Format "2006-01-02"}}' github.com/dmitshur-test/modtest5@latest
stdout '^github.com/dmitshur-test/modtest5 v0.5.0-alpha 2019-06-18$'
# If the module proxy contains only pseudo-versions, 'latest' should stat
# the version with the most recent timestamp — not the highest semantic
# version — and return its metadata.
env GOPROXY=file:///$WORK/tinyproxy
go list -m -json dmitri.shuralyov.com/test/modtest3@latest
cmp stdout $WORK/modtest3.json
go list -m -f '{{.Path}} {{.Version}} {{.Time.Format "2006-01-02"}}' dmitri.shuralyov.com/test/modtest3@latest
stdout '^dmitri.shuralyov.com/test/modtest3 v0.0.0-20181023043359-a85b471d5412 2018-10-22$'
-- $WORK/modtest5.list --
v0.0.0-20190619020302-197a620e0c9a
v0.5.0-alpha
v0.5.0-alpha.0.20190619023908-3da23a9deb9e
-- $WORK/modtest5.json --
{
"Path": "github.com/dmitshur-test/modtest5",
"Version": "v0.5.0-alpha",
"Time": "2019-06-18T19:04:46-07:00"
}
-- $WORK/tinyproxy/dmitri.shuralyov.com/test/modtest3/@v/list --
v0.1.0-0.20161023043300-000000000000
v0.0.0-20181023043359-a85b471d5412
@ -42,9 +37,3 @@ v0.0.0-20181023043359-a85b471d5412
"Version": "v0.0.0-20181023043359-a85b471d5412",
"Time": "2018-10-22T21:33:59-07:00"
}
-- $WORK/modtest3.json --
{
"Path": "dmitri.shuralyov.com/test/modtest3",
"Version": "v0.0.0-20181023043359-a85b471d5412",
"Time": "2018-10-22T21:33:59-07:00"
}

View File

@ -0,0 +1,108 @@
# 'go list -mod=vendor -retracted' reports an error.
go mod vendor
! go list -m -retracted -mod=vendor
stderr '^go list -retracted cannot be used when vendoring is enabled$'
rm vendor
# 'go list -retracted' reports an error in GOPATH mode.
env GO111MODULE=off
! go list -retracted
stderr '^go list -retracted can only be used in module-aware mode$'
env GO111MODULE=
# 'go list pkg' does not show retraction.
go list -f '{{with .Module}}{{with .Retracted}}retracted{{end}}{{end}}' example.com/retract
! stdout .
# 'go list -retracted pkg' shows retraction.
go list -retracted -f '{{with .Module}}{{with .Retracted}}retracted{{end}}{{end}}' example.com/retract
stdout retracted
# 'go list -m' does not show retraction.
go list -m -f '{{with .Retracted}}retracted{{end}}' example.com/retract
! stdout .
# 'go list -m -retracted' shows retraction.
go list -m -retracted -f '{{with .Retracted}}retracted{{end}}' example.com/retract
# 'go list -m mod@version' does not show retraction.
go list -m -f '{{with .Retracted}}retracted{{end}}' example.com/retract@v1.0.0-unused
! stdout .
# 'go list -m -retracted mod@version' shows an error if the go.mod that should
# contain the retractions is not available.
! go list -m -retracted example.com/retract/missingmod@v1.0.0
stderr '^go list -m: loading module retractions: example.com/retract/missingmod@v1.9.0:.*404 Not Found$'
go list -e -m -retracted -f '{{.Error.Err}}' example.com/retract/missingmod@v1.0.0
stdout '^loading module retractions: example.com/retract/missingmod@v1.9.0:.*404 Not Found$'
# 'go list -m -retracted mod@version' shows retractions.
go list -m -retracted example.com/retract@v1.0.0-unused
stdout '^example.com/retract v1.0.0-unused \(retracted\)$'
go list -m -retracted -f '{{with .Retracted}}retracted{{end}}' example.com/retract@v1.0.0-unused
stdout retracted
# 'go list -m mod@latest' selects a previous release version, not self-retracted latest.
go list -m -f '{{.Version}}{{with .Retracted}} retracted{{end}}' example.com/retract/self/prev@latest
stdout '^v1.1.0$'
# 'go list -m -retracted mod@latest' selects the self-retracted latest version.
go list -m -retracted -f '{{.Version}}{{with .Retracted}} retracted{{end}}' example.com/retract/self/prev@latest
stdout '^v1.9.0 retracted$'
# 'go list -m mod@latest' selects a pre-release version if all release versions are retracted.
go list -m -f '{{.Version}}{{with .Retracted}} retracted{{end}}' example.com/retract/self/prerelease@latest
stdout '^v1.9.1-pre$'
# 'go list -m -retracted mod@latest' selects the self-retracted latest version.
go list -m -retracted -f '{{.Version}}{{with .Retracted}} retracted{{end}}' example.com/retract/self/prerelease@latest
stdout '^v1.9.0 retracted$'
# 'go list -m mod@latest' selects a pseudo-version if all versions are retracted.
# TODO(golang.org/issue/24031): the proxy does not expose the pseudo-version,
# even if all release versions are retracted.
go list -m -e -f '{{.Error.Err}}' example.com/retract/self/pseudo@latest
stdout '^module example.com/retract/self/pseudo: no matching versions for query "latest"$'
# 'go list -m mod@latest' reports an error if all versions are retracted.
go list -m -e -f '{{.Error.Err}}' example.com/retract/self/all@latest
stdout '^module example.com/retract/self/all: no matching versions for query "latest"$'
# 'go list -m mod@<v1.10' selects a previous release version, not self-retracted latest.
# The @latest query is not special with respect to retractions.
go list -m -f '{{.Version}}{{with .Retracted}} retracted{{end}}' example.com/retract/self/prev@<v1.10
stdout '^v1.1.0$'
# 'go list -m -versions' hides retracted versions.
go list -m -versions example.com/retract
stdout '^example.com/retract v1.0.0-good v1.1.0$'
# 'go list -m -retracted -versions' shows retracted versions.
go list -m -retracted -versions example.com/retract
stdout '^example.com/retract v1.0.0-bad v1.0.0-good v1.0.0-unused v1.1.0$'
# 'go list -m -u -versions' loads retractions and does not show retracted versions.
go list -m -u -versions example.com/retract
stdout '^example.com/retract v1.0.0-good v1.1.0$'
go list -m -u -versions -f '{{with .Retracted}}retracted{{end}}' example.com/retract
stdout retracted
# 'go list -m -u' shows retraction.
go list -m -u -f '{{with .Retracted}}retracted{{end}}' example.com/retract
stdout retracted
# 'go list -m -u' does not suggest an update to a self-retracted latest version.
go list -m -u -f '{{with .Update}}{{.Version}}{{with .Retracted}} retracted{{end}}{{end}}' example.com/retract/self/prev@v1.0.0-bad
stdout '^v1.1.0$'
-- go.mod --
module example.com/use
go 1.15
require example.com/retract v1.0.0-bad
-- use.go --
package use
import _ "example.com/retract"

View File

@ -0,0 +1,51 @@
# If the latest unretracted version of a module is replaced, 'go list' should
# obtain retractions from the replacement.
# The latest version, v1.9.0, is not available on the proxy.
! go list -m -retracted example.com/retract/missingmod
stderr '^go list -m: loading module retractions: example.com/retract/missingmod@v1.9.0:.*404 Not Found$'
# If we replace that version, we should see retractions.
go mod edit -replace=example.com/retract/missingmod@v1.9.0=./missingmod-v1.9.0
go list -m -retracted -f '{{range .Retracted}}{{.}}{{end}}' example.com/retract/missingmod
stdout '^bad version$'
# If we replace the retracted version, we should not see a retraction.
go mod edit -replace=example.com/retract/missingmod=./missingmod-v1.9.0
go list -m -retracted -f '{{if not .Retracted}}good version{{end}}' example.com/retract/missingmod
stdout '^good version$'
# If a replacement version is retracted, we should see a retraction.
# It should appear in both the replaced module and the replacement, as other
# fields like GoMod do.
go list -m -retracted -f '{{range .Retracted}}{{.}}{{end}}' example.com/retract
! stdout .
go list -m -retracted -f '{{if .Replace}}replaced{{end}}' example.com/retract
! stdout .
go mod edit -replace example.com/retract@v1.0.0-good=example.com/retract@v1.0.0-bad
go list -m -retracted -f '{{range .Retracted}}{{.}}{{end}}' example.com/retract
stdout '^bad$'
go list -m -retracted -f '{{with .Replace}}{{range .Retracted}}{{.}}{{end}}{{end}}' example.com/retract
stdout '^bad$'
-- go.mod --
module m
go 1.14
require (
example.com/retract v1.0.0-good
example.com/retract/missingmod v1.0.0
)
-- missingmod-v1.0.0/go.mod --
module example.com/retract/missingmod
go 1.14
-- missingmod-v1.9.0/go.mod --
module example.com/retract/missingmod
go 1.14
// bad version
retract v1.0.0