3

我想用 go modules tools.go “工具作为依赖项”替换retool 。但是,当我的开发人员和 CI env 都使用不同的操作系统时,我很难理解这是如何工作的。

我想确保每个环境都使用完全相同版本的工具。

举个具体的例子,我的应用需要 protoc 编译器通过 github.com/golang/protobuf/protoc-gen-go 生成 go 代码。我有 3 个操作系统,都需要使用 protoc-gen-go 插件/生成器执行 protoc:

  1. 瑞恩:使用 MacOS
  2. 乔:Linux(Ubuntu)
  3. CI:Linux(CentOS)

我目前使用 retool 来确保所有环境都锁定在相同版本的工具上(本例中的 protoc-gen-go):

retool do build/bin/protoc -Ibuild/protoc/include -I. rpc/platform/platform.proto --go_out=.

我的新 go 模块/“作为依赖项的工具”设置

工具.go:

// +build tools

package tools

import (
    _ "github.com/golang/protobuf/protoc-gen-go"
)

设置将使用的路径go install

export GOBIN=$PWD/bin

安装:

go install github.com/golang/protobuf/protoc-gen-go

如果 Ryan 运行go install ..MacOSbin/protoc-gen-go可执行文件,则会创建。

问题

  1. 此时,为什么protoc-gen-gogo.mod 中没有列出工具版本(或 git hash)?
  2. 当 Joe 克隆应用程序存储库时,他如何获取和编译 Ryan 使用的相同版本的 protoc-gen-go?
  3. 如何protoc知道protoc-gen-go在我的目录中使用可执行生成器./bin
4

2 回答 2

3

我能够按照Go Modules 工具指南为 protoc(和Twirp之类的插件)构建供应商工具,并为protoc二进制文件加上一点 Makefile-Fu 。

一个完整的工作示例可以在 Aspiration Labs pyggpot repo中找到。以下是基本细节。值得注意的是:为某些工具设置正确的导入路径非常繁琐,但最终还是成功了。

protoc其本身而言,我在 Makefile 中提供二进制版本并将其设置到一个tools/bin目录中:

TOOLS_DIR := ./tools
TOOLS_BIN := $(TOOLS_DIR)/bin

# protoc
PROTOC_VERSION := 3.7.1
PROTOC_PLATFORM := osx-x86_64
PROTOC_RELEASES_PATH := https://github.com/protocolbuffers/protobuf/releases/download
PROTOC_ZIP := protoc-$(PROTOC_VERSION)-$(PROTOC_PLATFORM).zip
PROTOC_DOWNLOAD := $(PROTOC_RELEASES_PATH)/v$(PROTOC_VERSION)/$(PROTOC_ZIP)
PROTOC := $(TOOLS_BIN)/protoc

# protoc
$(PROTOC): $(TOOLS_DIR)/$(PROTOC_ZIP)
    unzip -o -d "$(TOOLS_DIR)" $< && touch $@  # avoid Prerequisite is newer than target `tools/bin/protoc'.

$(TOOLS_DIR)/$(PROTOC_ZIP):
    curl --location $(PROTOC_DOWNLOAD) --output $@

PROTOC_PLATFORM字符串可以通过诸如操作系统检测 makefile之类的东西自动化。我们使用的版本位于https://github.com/aspiration-labs/pyggpot/blob/master/build/makefiles/osvars.mk

继续构建 go 工具。创建一个类似的tools.go东西

// +build tools

package tools

import (
    // protocol buffer compiler plugins
    _ "github.com/golang/protobuf/protoc-gen-go"
    _ "github.com/twitchtv/twirp/protoc-gen-twirp"
    _ "github.com/twitchtv/twirp/protoc-gen-twirp_python"
    _ "github.com/thechriswalker/protoc-gen-twirp_js"
)

注意:该// +build tools标签将go build避免在您的最终构建中过度构建工具导入。

最后,一些代码来构建你的 go 工具:

# go installed tools.go
GO_TOOLS := github.com/golang/protobuf/protoc-gen-go \
            github.com/twitchtv/twirp/protoc-gen-twirp \
            github.com/twitchtv/twirp/protoc-gen-twirp_python \
            github.com/thechriswalker/protoc-gen-twirp_js \

# tools
GO_TOOLS_BIN := $(addprefix $(TOOLS_BIN), $(notdir $(GO_TOOLS)))
GO_TOOLS_VENDOR := $(addprefix vendor/, $(GO_TOOLS))

setup_tools: $(GO_TOOLS_BIN)

$(GO_TOOLS_BIN): $(GO_TOOLS_VENDOR)
    GOBIN="$(PWD)/$(TOOLS_BIN)" go install -mod=vendor $(GO_TOOLS)

最后,make setup运行go mod vendor和处理上述目标的目标。

setup: setup_vendor $(TOOLS_DIR) $(PROTOC) setup_tools

# vendor
setup_vendor:
    go mod vendor

$(TOOLS_DIR):
    mkdir -v -p $@
于 2019-06-18T01:14:13.687 回答
0

Go 模块与 .go 文件的导入一起使用。如果他们找到导入,他们将自动下载满足您要求的最新版本。您必须阅读https://github.com/golang/go/wiki/Modules并了解自 Go 1.11 及更高版本以来模块的工作原理。

此时,为什么 protoc-gen-go 工具版本(或 git hash)没有在 go.mod 中列出?

这是因为就 Go 模块而言,protoc-gen-go 只是一个外部工具。您不导入golang/protobuf/tree/master/protoc-gen-go它生成的代码。

当 Joe 克隆应用程序存储库时,他如何获取和编译 Ryan 使用的相同版本的 protoc-gen-go?

利用:

GIT_TAG="v1.2.0" # change as needed
go get -d -u github.com/golang/protobuf/protoc-gen-go
git -C "$(go env GOPATH)"/src/github.com/golang/protobuf checkout $GIT_TAG
go install github.com/golang/protobuf/protoc-gen-go

在用户的每台机器上安装特定版本。可能会编写一个自动化该过程的构建脚本。

protoc 如何知道在我的 ./bin 目录中使用 protoc-gen-go 可执行文件生成器?

来自 github 文档:除非设置了 $GOBIN,否则编译器插件 protoc-gen-go 将安装在 $GOPATH/bin 中。它必须在您的 $PATH 中,以便协议编译器 protoc 找到它。

于 2019-06-17T21:05:25.000 回答