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: //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 版本的 //github.com/googleapis/googleapis
    # 並且定義其名字為 GOOGLE_APIS
    # 在 importPaths 中可以通過 $GOOGLE_APIS 來引用它
    GOOGLE_APIS: //github.com/googleapis/googleapis@27156597fdf4fb77004434d4409154a230dc9a32
    # 定義依賴 226206f39bd7276e88ec684ea0028c18ec2c91ae 版本的 //github.com/gogo/protobuf
    # 並且定義其名字為 GOGO_PROTOBUF
    # 在 importPaths 中可以通過 $GOGO_PROTOBUF 來引用它
    GOGO_PROTOBUF: //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: //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: //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'
        - ""