PowerProto: gRPC工具链(protoc, protoc-gen-go)的一键安装与版本控制

🐱‍👓PowerProto: gRPC工具链(protoc, protoc-gen-go)的一键安装与版本控制

goreport.png totalline.png lastcommit.png godoc.png

中文 | English

exmaple.gif

项目地址:🎉 An awesome version control tool for protoc and its related plugins. (github.com/storyicon/powerproto)

PowerProto主要用于解决下面三个问题:

  1. 降低gRPC的使用门槛与使用成本。
  2. 解决protoc以及其相关插件(比如protoc-gen-go、protoc-gen-grpc-gateway)的版本控制问题。
  3. 高效管理proto的编译,实现多平台兼容、一键安装与编译。

🎉 功能

  1. 实现protoc的一键安装与多版本管理。
  2. 实现protoc相关插件(比如protoc-gen-go)的一键安装与多版本管理。
  3. 通过配置文件管理proto的编译,而非shell脚本,提高可读性与兼容性。
  4. 引导式生成配置文件,跨平台兼容,一份配置在多个平台均可以实现一键编译。
  5. 支持批量、递归编译proto文件,提高效率。
  6. 跨平台支持PostAction,可以在编译完成之后执行一些常规操作(比如替换掉所有生成文件中的"omitempty")。
  7. 支持PostShell,在编译完成之后执行特定的shell脚本。
  8. 支持 google api, gogo protobuf 等的一键安装与版本控制。

安装与依赖

  1. 目前版本的 PowerProto 依赖 go(>=1.16) 以及 git(未来可能会直接使用CDN拉取构建好的二进制),请确保运行环境中包含这两个命令。
  2. protoc的下载源是Github,PowerProto在下载protoc时尊重 HTTP_PROXYHTTPS_PROXY环境变量,如果遇到网络问题,请自行配置代理。
  3. 在查询protoc的版本列表时,会对github.com使用git ls-remote,如果遇到网络问题,请自行为git配置代理。
  4. 在当前版本,下载和查询插件版本均依赖go命令,所以如果遇到网络问题,请自行配置 GOPROXY环境变量。
  5. 默认会使用 用户目录/.powerproto作为安装目录,用于放置下载好的各种插件以及全局配置,可以通过 POWERPROTO_HOME环境变量来修改安装目录。
  6. 如果认为powerproto名字太长,可以通过alias成一个更简单的名字来提高输入效率,比如没有人会介意你叫它pp

一、通过Go进行安装

直接执行下面的命令即可进行安装:

go install github.com/storyicon/powerproto/cmd/powerproto@latest

二、开箱即用版本

可以通过 Github Release Page 下载开箱即用版本。

命令介绍

你可以通过 powerproto -h 来查看帮助,比如:

powerproto -h
powerproto init -h
powerproto tidy -h
powerproto build -h
powerproto env -h

它的好处是命令行中的文档永远和你的二进制版本保持一致。而Github上的文档可能会一直是对应最新的二进制。

一、初始化配置

可以通过下面的命令进行配置的初始化:

powerproto init

二、整理配置

可以通过下面的命令整理配置:

powerproto tidy

它将会从当前目录开始向父级目录搜索名为 powerproto.yaml 的配置文件,并对配置进行读取和整理。

你也可以指定整理哪个配置文件:

powerproto tidy [the path of proto file]

整理配置主要包含两个操作:

  1. 通过查询,将版本中的latest替换为真实的最新版本号。
  2. 安装配置文件中定义的所有依赖。

支持通过 -d 参数来进入到debug模式,查看更详细的日志。

三、编译Proto文件

可以通过下面的命令进行Proto文件的编译:

// 编译指定的proto文件
powerproto build xxxx.proto

// 编译当前目录下的所有proto文件
powerproto build .

// 递归编译当前目录下的所有proto文件,包括子文件夹。
powerproto build -r .

其执行逻辑是,对于每一个proto文件,从其文件所在目录开始向父级目录寻找 powerproto.yaml 配置文件:

  1. 对于找到的配置文件,与其中的scope进行匹配,如果匹配则采用。
  2. 检查并安装配置文件中声明的依赖。
  3. 根据配置文件中的pluginsprotocoptionsimportPaths等配置对proto文件进行编译。 当所有的proto文件都编译完成之后,如果你指定了 -p 参数,还会进行PostActionPostShell的执行。

注意:protoc执行的工作目录默认是proto文件匹配到的配置文件所在的目录,它相当于你在配置文件所在目录执行protoc命令。你可以通过配置文件中的 protocWorkDir 来进行修改。

支持通过 -d 参数来进入到debug模式,查看更详细的日志。
支持通过 -y 参数来进入到dryRun模式,只打印命令而不真正执行,这对于调试非常有用。

四、查看环境变量

如果你的命令一直卡在某个状态,大概率是出现网络问题了。
你可以通过下面的命令来查看环境变量是否配置成功:

powerproto env

示例

比如你在 /mnt/data/hello 目录下拥有下面这样的文件结构:

$ pwd
/mnt/data/hello

$ tree
./apis
└── hello.proto
powerproto.yaml

powerproto.yaml 的文件内容是(你可以通过 powerproto init 命令很方便的生成配置文件):

scopes:
    - ./
protoc: latest
protocWorkDir: ""
plugins:
    protoc-gen-go: google.golang.org/protobuf/cmd/protoc-gen-go@latest
    protoc-gen-go-grpc: google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest
repositories:
    GOOGLE_APIS: https://github.com/googleapis/googleapis@75e9812478607db997376ccea247dd6928f70f45
options:
    - --go_out=.
    - --go_opt=paths=source_relative
    - --go-grpc_out=.
    - --go-grpc_opt=paths=source_relative
importPaths:
    - .
    - $GOPATH
    - $POWERPROTO_INCLUDE
    - $GOOGLE_APIS/github.com/googleapis/googleapis
postActions: []
postShell: ""

在任意目录执行:

powerproto build -r /mnt/data/hello/apis

你都可以得到编译后的文件

$ pwd
/mnt/data/hello

$ tree
./apis
├── hello.pb.go
├── hello.proto
└── hello_grpc.pb.go
powerproto.yaml

它相当于你在 powerproto.yaml 所在目录,执行:

$POWERPROTO_HOME/protoc/3.17.3/protoc --go_out=. \
--go_opt=paths=source_relative \
--go-grpc_out=. \
--go-grpc_opt=paths=source_relative \
--proto_path=/mnt/data/hello \
--proto_path=$GOPATH \
--proto_path=$POWERPROTO_HOME/include \
--proto_path=$POWERPROTO_HOME/gits/75e9812478607db997376ccea247dd6928f70f45/github.com/googleapis/googleapis \
--plugin=protoc-gen-go=$POWERPROTO_HOME/plugins/google.golang.org/protobuf/cmd/protoc-gen-go@v1.27.1/protoc-gen-go \
--plugin=protoc-gen-go-grpc=$POWERPROTO_HOME/plugins/google.golang.org/grpc/cmd/protoc-gen-go-grpc@v1.1.0/protoc-gen-go-grpc
/mnt/data/hello/apis/hello.proto

更多的例子可以参考 示例.

配置文件

配置文件用于描述编译proto文件时,各种依赖的版本以及参数等。

可以方便的通过 powerproto init进行配置文件的初始化。

解释

以下面这份配置文件为例:

# 必填,scopes 用于定义作用域,即当前配置项对项目中的哪些目录生效
scopes:
    - ./
# 必填,protoc的版本,可以填 latest,会自动转换成最新的版本
protoc: 3.17.3
# 选填,执行protoc命令的工作目录,默认是配置文件所在目录
# 支持路径中混用环境变量,比如$GOPATH
protocWorkDir: ""
# 选填,定义依赖的Git存储库
# 一般用于公共的protobuf库的依赖控制
repositories:
    # 定义依赖 27156597fdf4fb77004434d4409154a230dc9a32 版本的 https://github.com/googleapis/googleapis
    # 并且定义其名字为 GOOGLE_APIS
    # 在 importPaths 中可以通过 $GOOGLE_APIS 来引用它
    GOOGLE_APIS: https://github.com/googleapis/googleapis@27156597fdf4fb77004434d4409154a230dc9a32
    # 定义依赖 226206f39bd7276e88ec684ea0028c18ec2c91ae 版本的 https://github.com/gogo/protobuf
    # 并且定义其名字为 GOGO_PROTOBUF
    # 在 importPaths 中可以通过 $GOGO_PROTOBUF 来引用它
    GOGO_PROTOBUF: https://github.com/gogo/protobuf@226206f39bd7276e88ec684ea0028c18ec2c91ae
# 必填,代表scope匹配的目录中的proto文件,在编译时需要用到哪些插件
plugins:
    # 插件的名字、路径以及版本号。
    # 插件的地址必须是 path@version 的格式,version可以填latest,会自动转换成最新的版本。
    protoc-gen-deepcopy: istio.io/tools/cmd/protoc-gen-deepcopy@latest
    protoc-gen-go: google.golang.org/protobuf/cmd/protoc-gen-go@latest
    protoc-gen-go-json: github.com/mitchellh/protoc-gen-go-json@v1.0.0
    protoc-gen-grpc-gateway: github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-grpc-gateway@v2.5.0
# 必填,定义了编译proto文件时 protoc 的参数
options:
    - --go_out=paths=source_relative:.
    - --go-json_out=.
    - --deepcopy_out=source_relative:.
    - --grpc-gateway_out=.
    - --go-grpc_out=paths=source_relative:.
# 必填,定义了构建时 protoc 的引用路径,会被转换为 --proto_path (-I) 参数。
importPaths:
    # 特殊变量。代表当前配置文件所在文件夹
    - .
    # 环境变量。可以使用环境变量
    # 也支持 $GOPATH/include 这样的混合写法
    - $GOPATH
    - $POWERPROTO_INCLUDE
    # 特殊变量。引用待编译的proto文件所在的目录
    # 比如将要编译 /a/b/data.proto,那么 /a/b 目录将会被自动引用
    - $SOURCE_RELATIVE
    # 引用 repositories 中的 GOOGLE_APIS
    - $GOOGLE_APIS/github.com/googleapis/googleapis
    # 引用 repositories 中的 GOGO_PROTOBUF
    - $GOGO_PROTOBUF
# 选填,构建完成之后执行的操作,工作目录是配置文件所在目录
# postActions是跨平台兼容的
# 注意,必须在 powerproto build 时附加 -p 参数,才会执行配置文件中的postActions
postActions: []
# 选填,构建完成之后执行的shell脚本,工作目录是配置文件所在目录
# postShell不是跨平台兼容的。
# 注意,必须在 powerproto build 时附加 -p 参数,才会执行配置文件中的postShell
postShell: |
    // do something

匹配模式与工作目录

在构建proto文件时,将会从proto文件所在目录开始,向父级目录搜索 powerproto.yaml 配置文件,并与其中的 scope进行匹配,第一个匹配到的配置,将会被用于此proto文件的编译。
在执行protoc时(执行postActions、postShell时也是如此),是以配置文件所在目录作为工作目录的,即相当于你在这个目录执行protoc命令。

多配置组合

一个配置文件中支持填写多份配置,多份配置之间以 "---" 进行分割。

在下面的示例中,apis1目录使用的是v1.25.0的protoc-gen-go,而apis2目录使用的则是v1.27.0的protoc-gen-go。

scopes:
    - ./apis1
protoc: v3.17.3
protocWorkDir: ""
plugins:
    protoc-gen-go: google.golang.org/protobuf/cmd/protoc-gen-go@v1.25.0
    protoc-gen-go-grpc: google.golang.org/grpc/cmd/protoc-gen-go-grpc@v1.1.0
repositories:
    GOOGLE_APIS: https://github.com/googleapis/googleapis@75e9812478607db997376ccea247dd6928f70f45
options:
    - --go_out=.
    - --go_opt=paths=source_relative
    - --go-grpc_out=.
    - --go-grpc_opt=paths=source_relative
importPaths:
    - .
    - $GOPATH
    - $POWERPROTO_INCLUDE
    - $GOOGLE_APIS/github.com/googleapis/googleapis
postActions: []
postShell: ""

---

scopes:
    - ./apis2
protoc: v3.17.3
protocWorkDir: ""
plugins:
    protoc-gen-go: google.golang.org/protobuf/cmd/protoc-gen-go@v1.27.0
    protoc-gen-go-grpc: google.golang.org/grpc/cmd/protoc-gen-go-grpc@v1.1.0
repositories:
    GOOGLE_APIS: https://github.com/googleapis/googleapis@75e9812478607db997376ccea247dd6928f70f45
options:
    - --go_out=.
    - --go_opt=paths=source_relative
    - --go-grpc_out=.
    - --go-grpc_opt=paths=source_relative
importPaths:
    - .
    - $GOPATH
    - $POWERPROTO_INCLUDE
    - $GOOGLE_APIS/github.com/googleapis/googleapis
postActions: []
postShell: ""

PostAction

PostAction允许在所有的proto文件都编译完成之后,执行特定的操作。与PostShell相比,它是跨平台支持的。

为了安全起见,只有在执行 powerproto build时附加上 -p 参数,才会执行配置文件中定义的PostActionPostShell

目前,PostAction支持下面这些命令:

命令 描述 函数原型
copy 复制文件或文件夹 copy(src string, dest string) error
move 移动文件或文件夹 move(src string, dest string) error
remove 删除文件或文件夹 remove(path ...string) error
replace 批量替换文件中的字符串 replace(pattern string, from string, to string) error

1. copy

用于复制文件或文件夹,其函数原型为:

copy(src string, dest string) error

为了安全以及配置的兼容性,参数中只允许填写相对路径。

如果目标文件夹已经存在,将会合并。

下面的例子将会把配置文件所在目录下的a复制到b:

postActions:
    - name: copy
      args:
        - ./a
        - ./b

2. move

用于移动文件或文件夹,其函数原型为:

move(src string, dest string) error

为了安全以及配置的兼容性,参数中只允许填写相对路径。

如果目标文件夹已经存在,将会合并。

下面的例子将会把配置文件所在目录下的a移动到b:

postActions:
    - name: move
      args:
        - ./a
        - ./b

3. remove

用于删除文件或文件夹,其函数原型为:

remove(path ...string) error

为了安全以及配置的兼容性,参数中只允许填写相对路径。

下面的例子将会删除配置文件所在目录下的a、b、c:

postActions:
    - name: remove
      args:
        - ./a
        - ./b
        - ./c

4. replace

用于批量替换文件中的字符串,其函数原型为:

replace(pattern string, from string, to string) error

其中:

  • pattern是支持通配符的相对路径。
  • from是要被替换的字符串。
  • to是替换为的字符串。

下面的例子将会把apis目录以及其子目录下的所有go文件中的 ,omitempty 替换为空字符串:

postActions:
    - name: replace
      args:
        - ./apis/**/*.go
        - ',omitempty'
        - ""
posted @ 2021-07-30 16:04  公子扶摇  阅读(2372)  评论(0编辑  收藏  举报