‍PowerProto: gRPC工具鏈(protoc, protoc-gen-go)的一鍵安裝與版本控制

中文 | English

專案地址: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/[email protected]/protoc-gen-go \
--plugin=protoc-gen-go-grpc=$POWERPROTO_HOME/plugins/google.golang.org/grpc/cmd/[email protected]/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/[email protected]
protoc-gen-grpc-gateway: github.com/grpc-ecosystem/grpc-gateway/v2/[email protected]
# 必填,定義了編譯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/[email protected]
protoc-gen-go-grpc: google.golang.org/grpc/cmd/[email protected]
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/[email protected]
protoc-gen-go-grpc: google.golang.org/grpc/cmd/[email protected]
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'
- ""