cmd/go: 对于不包含Go包的供应商子目录,报告"awkward "list -json"错误

svmlkihl  于 2个月前  发布在  Go
关注(0)|答案(5)|浏览(26)

你正在使用的Go版本是什么( go version )?

$ go version
go version go1.20 darwin/amd64

这个问题在最新版本的发布中是否重现?

是的

你正在使用什么操作系统和处理器架构( go env )?

go env 输出

$ go env
GOOS="darwin"
GOARCH="amd64"

你做了什么?

运行以下命令创建一个模块,该模块为其依赖项提供供应商,然后运行 go list -e -json :

mkdir go-list-repro && cd $_
echo "module go-list-repro" > go.mod
echo 'package main; import _ "golang.org/x/tools/go/packages"; func main(){}' > main.go
go mod tidy
go mod vendor
go list -e -json golang.org/x/tools

你期望看到什么?

请求的模块的JSON结构信息应包含表示模块目录的 Dir 字段(路径应在供应商目录中)。

你看到了什么?

作为输出的一部分打印的JSON结构没有 Dir 字段:

go: finding module for package golang.org/x/tools
{
	"ImportPath": "golang.org/x/tools",
	"Match": [
		"golang.org/x/tools"
	],
	"Incomplete": true,
	"Error": {
		"ImportStack": [],
		"Pos": "",
		"Err": "cannot query module due to -mod=vendor\n\t(Go version in go.mod is at least 1.14 and vendor directory exists.)"
	}
}

这是在相同目录下使用Go 1.19的命令的输出:

{
	"Dir": "/Volumes/git/go/src/github.com/nmiyake/go-list-repro/vendor/golang.org/x/tools",
	"ImportPath": "golang.org/x/tools",
	"Target": "/Volumes/git/go/pkg/darwin_amd64/github.com/nmiyake/go-list-repro/vendor/golang.org/x/tools.a",
	"Root": "/Volumes/git/go",
	"Match": [
		"golang.org/x/tools"
	],
	"Incomplete": true,
	"Error": {
		"ImportStack": [
			"golang.org/x/tools"
		],
		"Pos": "",
		"Err": "no Go files in /Volumes/git/go/src/github.com/nmiyake/go-list-repro/vendor/golang.org/x/tools"
	}
}

背景是,我编写的依赖于此代码的代码正在执行以下操作:

  • "给定一个本地模块,该模块为其依赖项提供供应商,找到所有导入模块在供应商目录中的路径"

Go 1.19及更高版本通过 go list 允许这样做,但Go 1.20的行为更改破坏了这种工作流程,我不知道为什么在这种情况下输出会改变。
错误 "cannot query module due to -mod=vendor\n\t(Go version in go.mod is at least 1.14 and vendor directory exists.)" 也是误导性的,因为如果查询更改为包( golang.org/x/tools/go/packages ),则 list 操作成功并打印包信息(尽管仍然满足“go.mod中的Go版本至少为1.14且存在供应商目录”的条件)。

k2fxgqgv

k2fxgqgv2#

Dir 字段不适用于模块,仅适用于软件包,而 golang.org/x/tools 不是一个软件包(它没有 .go 源文件)。
删除 Target 字段可能是修复 #37015 的副作用,该修复有意解决了导致在模块模式下 Target 字段不一致填充的错误。

5ktev3wc

5ktev3wc3#

是的,我理解这里的目标不是包,但看起来处理方式发生了变化,似乎是不正确的——这是一个更具体的“在模块/包路径上调用go list时出现的行为问题”,该路径不包含被引入的Go文件。
在Go 1.19中,输出正确地将"Err": "no Go files in /Volumes/git/go/src/github.com/nmiyake/go-list-repro/vendor/golang.org/x/tools"作为错误,并仍然填充了像Dir这样的字段(这回答了问题“如果这个目录中有Go文件,那么这个模块/包在磁盘上的目录是什么?”)。我理解在错误情况下填充Dir字段不一定是一种保证/值得恢复的行为,所以虽然我觉得它很有用,但我知道这种行为不会被恢复。
相比之下,Go 1.20中的"cannot query module due to -mod=vendor\n\t(Go version in go.mod is at least 1.14 and vendor directory exists.)"错误输出似乎确实不正确。

qij5mzcb

qij5mzcb4#

vendor/modules.txt 列出了包含 Go 包的目录,但该列表不包括指定的包。如果我们不期望在那里找到包(尽管今天我们可能错误地这样做),那么我们甚至不应该花费 I/O 操作来读取该目录。如果我们没有读取(或不应该读取)该目录,那么我们也不应该声称该目录是否包含 Go 源文件。
因此,我认为 no Go files 错误是错误的,尽管我确实同意 cannot query module 错误消息在 vendor 模式下也不是特别有帮助。🤔

tquggr8v

tquggr8v5#

感谢您提供的上下文信息。结合观察引入此行为的更改,我现在对其中的机制有了更好的理解。

行为差异是由于 importFromModules 更改导致的 src/cmd/go/internal/modload/import.go 的变化,关键点位于:https://go-review.googlesource.com/c/go/+/434095/11/src/cmd/go/internal/modload/import.go#326。

在更改之前和之后,都会执行以下操作来处理供应商目录(因此发生了 I/O):

vendorDir, vendorOK, _ := dirInModule(path, "", filepath.Join(modRoot, "vendor"), false)

更改之前,计算后的 vendorDir 值总是被返回。更改后,如果 vendorOK 不为真,则返回 "" 作为目录,而不是 vendorDir

我会将此问题保持开放状态,因为我确实认为当前输出仍有改进的空间,但同时也理解我所消费的行为是一种偶然发生且工作正常但并非技术上正确的行为,因此我会在我这边找到解决方法。谢谢。

相关问题