Go Wiki: Gomote
gomote 命令是 Go 构建器基础设施的客户端。它是远程 Go 构建器机器的遥控器。
安装
$ go install golang.org/x/build/cmd/gomote@latest # Go 1.16 and later
用法
gomote 工具最基本的用法只涉及几个步骤
- 创建一个实例。
- 将代码推送到实例。
- 在实例上运行命令。
运行带有 -list
标志的 create
命令将列出可用的实例类型。
$ gomote create -list
(list tons of builder types)
然后,可以通过指定实例类型来创建实例。实例的名称将打印到 stdout,因此结果可以存储在环境变量中。(可能还有其他日志消息,但它们会输出到 stderr,并且每行都带有 '#' 前缀。)
$ gomote create gotip-linux-amd64
# still creating gotip-linux-amd64 (1) after 5s; 0 requests ahead of you
user-gotip-linux-amd64-0
有了该实例的名称,您现在可以将 GOROOT 推送到实例并安装一个引导工具链。您同步的仓库将出现在 $WORKDIR
(所有 gomote 操作的默认目录)的 go
子目录下。引导工具链将始终位于 go1.4
子目录中(即使引导工具链不是来自版本 1.4)。
$ GOROOT=/path/to/local/go/repo gomote push user-gotip-linux-amd64-0
$ gomote ls user-gotip-linux-amd64-0
go
go1.4
请注意,push
实际上是一个“同步”操作,因此下次您执行 push 时,gomote 工具只会推送发生更改的内容(添加、修改或删除的文件)。
安装了工具链后,您现在可以通过在实例上运行命令来构建它。run
命令允许您指定要运行的可执行文件。可执行文件必须相对于 $WORKDIR
(例如 go/bin/go
)或通过绝对路径(例如 /bin/bash
)指定。然后,该可执行文件将在包含该可执行文件的目录作为其当前工作目录的环境下运行。
$ gomote run user-gotip-linux-amd64-0 go/src/make.bash
要运行构建好的 Go 工具链,请使用 go/bin/go
。
$ gomote run user-gotip-linux-amd64-0 go/bin/go test -run="TestSomething" -v runtime
您还可以通过 run
命令的标志指定工作目录和环境变量,这些标志将在命令执行前应用。
请注意,gomote 实例在闲置 30 分钟后将自动消失。使用 list
命令可以查看剩余时间。
$ gomote list
user-gotip-linux-amd64-0 gotip-linux-amd64 gotip-linux-amd64 expires in 10m27.339494527s
如果没有其他命令正在针对某个实例运行,可以使用 ping
命令使其保持活动状态。
有关每个命令的更多信息,请运行 gomote help <command>
。有关更多命令,请运行 gomote help
。
构建器类型
可用的构建器类型遵循一定的结构,大致为 $GOBRANCH-($REPO-)?$GOOS-$GOARCH(_$OS)-$EXTRA
。
关于这些名称的一些有用说明。
- 不同的
$GOBRANCH
主要修改预安装的工具版本,例如引导 Go 工具链。 - 带有
$REPO
的构建器类型会将指定的仓库下载到工作根目录的 tip-of-tree 版本。
直接调试 buildlets
create
命令联系构建协调器 (farmer.golang.org) 并请求它为您创建一个 buildlet。所有后续命令(例如 gomote run
或 gomote ls
)都通过协调器代理您的请求。要直接访问 buildlet(例如,在处理 buildlet 代码时),您可以跳过 gomote create
步骤,使用特殊的构建器名称 <build-config-name>@ip[:port>
,例如 windows-amd64-2008@10.1.5.3
。
分组
实例可以在命名分组中进行管理,命令会广播到分组中的所有实例。
分组可以通过全局标志 -group
或通过 GOMOTE_GROUP
环境变量指定。-group
标志必须始终指定一个有效的分组,而 GOMOTE_GROUP
可能包含一个无效的分组。一个实例可以属于多个分组。
分组可以使用“group”子命令进行显式管理,但在大多数情况下,有几个快捷方式可以避免这种显式管理
create
命令可以使用-new-group
标志为实例创建一个新的分组。- 如果
GOMOTE_GROUP
中指定的分组不存在且没有显式指定其他分组,create
命令将自动创建该分组。 destroy
命令除了销毁实例外,还可以使用-destroy-group
标志销毁分组。
因此,使用分组最简单的方法就是设置 GOMOTE_GROUP
环境变量
$ export GOMOTE_GROUP=debug
$ gomote create gotip-linux-amd64
$ GOROOT=/path/to/goroot gomote push
$ gomote run go/src/make.bash
如本例所示,即使分组只包含一个实例,分组也很有用:它可以极大地缩短大多数 gomote 命令。
技巧与窍门
一般
create
命令接受 -setup
标志,该标志也会推送 GOROOT
并为实例运行相应的 make.bash
等效命令。
示例
$ GOROOT=/path/to/my/goroot gomote create -setup gotip-linux-amd64
# Creating user-gotip-linux-amd64-0...
# Pushing /path/to/my/goroot to user-gotip-linux-amd64-0
# Running make.bash on user-gotip-linux-amd64-0...
create
命令接受 -count
标志,用于一次创建多个实例。
示例
$ gomote create -count=3 gotip-linux-amd64
# Creating user-gotip-linux-amd64-0...
# Creating user-gotip-linux-amd64-1...
# Creating user-gotip-linux-amd64-2...
run
命令接受 -collect
标志,用于自动将命令的输出写入当前工作目录的文件中,以及实例完整文件树的副本。此命令对于以“设置后即忘”的方式捕获长时间运行命令的输出很有用。
示例
$ gomote run -collect user-gotip-linux-amd64-0 /bin/bash -c 'echo hi'
# Writing output to user-gotip-linux-amd64-0.stdout...
$ cat user-gotip-linux-amd64-0.stdout
hi
$ ls user-gotip-linux-amd64-0.tar.gz
user-gotip-linux-amd64-0.tar.gz
run
命令接受 -until
标志,用于持续执行命令直到命令的输出匹配某个模式。这对于重现罕见问题很有用,特别是与 -collect
结合使用时。
示例
$ gomote run -until 'FAIL' -collect user-gotip-linux-amd64-0 go/bin/go test -run 'TestFlaky' -count=1000 runtime
# Writing output to user-gotip-linux-amd64-0.stdout...
$ cat user-gotip-linux-amd64-0.stdout
...
--- FAIL: TestFlaky ---
...
$ ls user-gotip-linux-amd64-0.tar.gz
user-gotip-linux-amd64-0.tar.gz
请注意,无论是否有附加标志,run
命令始终将输出流式传输到临时文件,以避免因终端回滚而丢失输出。它总是打印文件位置。
重现罕见故障
结合上面的一些技巧并利用分组,持续对某些测试进行尝试以重现罕见故障会容易得多。例如
$ export GOMOTE_GROUP=debug
$ GOROOT=/path/to/goroot gomote create -setup -count=10 gotip-linux-amd64
$ gomote run -until='unexpected return pc' -collect go/bin/go run -run="TestFlaky" -count=100 runtime
Darwin
已知 Darwin gomotes 需要几分钟来设置,即使有可用机器。这是由于设置 Xcode 需要额外时间。
Windows
$ gomote run -path '$PATH,$WORKDIR/go/bin' $MOTE go/src/make.bat
$ gomote run -path '$PATH,$WORKDIR/go/bin' $MOTE go/bin/go.exe test cmd/go -short
注意:wiki 的先前版本建议为 gomote ‘run’ 命令设置 GOROOT(例如 “-e GOROOT=%WORKDIR%\go”);现在不推荐这样做(会导致 Go 命令缓存出现问题)。
Windows 上的子仓库
$ tar --exclude .git -C ~/go/src/ -zc golang.org/x/tools | gomote puttar -dir=gopath/src $MOTE -
$ gomote run -e 'GOPATH=%WORKDIR%\gopath' $MOTE go/bin/go test -run=TestFixImportsVendorPackage golang.org/x/tools/imports
如果通过 ssh 连接到机器,这些环境变量可能会很方便
$ set GOPATH=%WORKDIR%\gopath
$ set PATH=%PATH%;%WORKDIR%\gopath\bin;%WORKDIR%\go\bin
$ set CGO_ENABLED=0
Unix 上的子仓库
在 $MOTE 上测试 golang.org/x/sys/unix
$ tar -C $GOPATH/src/ -zc golang.org/x/sys/unix | gomote puttar -dir=gopath/src $MOTE
$ gomote run -e 'GOPATH=/tmp/workdir/gopath' -dir 'gopath/src/golang.org/x/sys/unix' $MOTE go/bin/go test -v golang.org/x/sys/unix
(GOPATH 部分用于 GOPATH 兼容模式;-dir
用于模块模式,它会在工作目录及向上查找 go.mod
)
Android
export MOTE=`gomote create android-arm64-wikofever`
gomote push $MOTE
gomote run $MOTE go/src/make.bash
PATH 必须包含由 make.bash 构建的 exec wrapper,go_android_*_exec
。
gomote run -path '$PATH,$WORKDIR/go/bin' $MOTE go/bin/go test math/big
关于 buildlets
https://farmer.golang.org/builders 列出了关于每个 buildlet 如何部署和配置的信息。这些信息来自 golang.org/x/build/dashboard 和 golang.org/x/build/env。
访问权限
自 2025 年 1 月起,gomote 访问权限将自动授予拥有 Approvers 访问权限的贡献者。
2022 年 8 月,部署了新的基础设施,需要移除先前已批准用户的所有 gomote 访问权限。如果您仍然需要访问权限,请重新申请。
要申请 gomote 服务访问权限,请提交一个新 issue (https://golang.ac.cn/issue/new?title=access:+&body=See+https://golang.ac.cn/wiki/Gomote%23access.) 并说明您用于登录 Gerrit 的 Google 帐户。提供的帐户仅用于身份验证。
首次调用命令时会触发身份验证
$ gomote create gotip-linux-amd64
Please visit https://www.google.com/device in your browser and enter verification code:
ABCD-4567
...
login 命令也会启动身份验证流程
$ gomote login
Please visit https://www.google.com/device in your browser and enter verification code:
ABCD-4567
...
使用提供的链接打开浏览器后,用户必须使用 Google 帐户进行身份验证,并将验证码粘贴到浏览器中。稍等片刻后,客户端将完成身份验证。
gomote ssh
gomote ssh
命令使用专门为 gomote 创建的 SSH 密钥。首次使用 gomote ssh
时,会创建一组密钥并存储在本地用户配置目录中。您可能会被要求为密钥设置密码(密码不是必需的)。SSH 功能通过 OpenSSH 证书认证进行操作,不需要任何额外配置。并非所有构建器类型都支持 gomote ssh
。
此内容是 Go Wiki 的一部分。