mirror of
https://github.com/TECHNOFAB11/powerproto.git
synced 2025-12-11 23:50:04 +01:00
init
Signed-off-by: storyicon <yuanchao@bilibili.com>
This commit is contained in:
commit
9aac714c32
47 changed files with 5480 additions and 0 deletions
28
.github/workflows/build.yml
vendored
Normal file
28
.github/workflows/build.yml
vendored
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
name: Go
|
||||
|
||||
on:
|
||||
push:
|
||||
tags: [ '**' ]
|
||||
pull_request:
|
||||
tags: [ '**' ]
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: 1.16
|
||||
|
||||
- name: Build
|
||||
run: make build
|
||||
|
||||
- name: Release
|
||||
uses: fnkr/github-action-ghr@v1
|
||||
if: startsWith(github.ref, 'refs/tags/')
|
||||
env:
|
||||
GHR_COMPRESS: gz
|
||||
GHR_PATH: /home/runner/work/powerproto/powerproto/dist/
|
||||
GITHUB_TOKEN: ${{ secrets.ACTIONS_SECRET }}
|
||||
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
.vscode
|
||||
.idea
|
||||
dist
|
||||
19
Makefile
Normal file
19
Makefile
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
VERSION=$(shell git describe --tags)
|
||||
GIT_REVISION=$(shell git rev-parse --short HEAD)
|
||||
GIT_BRANCH := $(shell git rev-parse --abbrev-ref HEAD)
|
||||
BUILD_DATE=$$(date +%Y-%m-%d-%H:%M)
|
||||
GO_FLAGS := -ldflags "-X main.BuildDate=$(BUILD_DATE) -X main.Branch=$(GIT_BRANCH) -X main.Revision=$(GIT_REVISION) -X main.Version=$(VERSION) -extldflags \"-static\" -s -w" -tags netgo
|
||||
|
||||
# Generate binaries for a powerproto release
|
||||
.PHONY: build
|
||||
build:
|
||||
rm -fr ./dist/
|
||||
mkdir -p ./dist
|
||||
GOOS="linux" GOARCH="amd64" CGO_ENABLED=0 go build $(GO_FLAGS) -o ./dist/powerproto-linux-amd64 ./cmd/powerproto
|
||||
GOOS="linux" GOARCH="arm64" CGO_ENABLED=0 go build $(GO_FLAGS) -o ./dist/powerproto-linux-arm64 ./cmd/powerproto
|
||||
GOOS="linux" GOARCH="arm" CGO_ENABLED=0 go build $(GO_FLAGS) -o ./dist/powerproto-linux-arm ./cmd/powerproto
|
||||
GOOS="linux" GOARCH="386" CGO_ENABLED=0 go build $(GO_FLAGS) -o ./dist/powerproto-linux-x86 ./cmd/powerproto
|
||||
GOOS="windows" GOARCH="386" CGO_ENABLED=0 go build $(GO_FLAGS) -o ./dist/powerproto-windows-x86.exe ./cmd/powerproto
|
||||
GOOS="windows" GOARCH="amd64" CGO_ENABLED=0 go build $(GO_FLAGS) -o ./dist/powerproto-windows-amd64.exe ./cmd/powerproto
|
||||
GOOS="darwin" GOARCH="amd64" CGO_ENABLED=0 go build $(GO_FLAGS) -o ./dist/powerproto-darwin-amd64 ./cmd/powerproto
|
||||
GOOS="darwin" GOARCH="arm64" CGO_ENABLED=0 go build $(GO_FLAGS) -o ./dist/powerproto-darwin-arm64 ./cmd/powerproto
|
||||
429
README.md
Normal file
429
README.md
Normal file
|
|
@ -0,0 +1,429 @@
|
|||
# PowerProto
|
||||
|
||||
[](https://goreportcard.com/report/github.com/storyicon/powerproto)   [](https://godoc.org/github.com/storyicon/powerproto)
|
||||
|
||||
**English** | [中文](README_CN.md)
|
||||
|
||||

|
||||
|
||||
PowerProto is used to solve the following three main problems:
|
||||
|
||||
1. lower the usage threshold and usage cost of gRPC.
|
||||
2. solve the version control problem of protoc and its related plugins (such as protoc-gen-go, protoc-gen-grpc-gateway).
|
||||
3. efficiently manage the compilation of proto to achieve multi-platform compatibility, one-click installation and compilation.
|
||||
|
||||
|
||||
- [PowerProto](#powerproto)
|
||||
- [Features](#features)
|
||||
- [Installation and Dependencies](#installation-and-dependencies)
|
||||
- [I. Installation via Go](#i-installation-via-go)
|
||||
- [II. out-of-the-box version](#ii-out-of-the-box-version)
|
||||
- [Command Introduction](#command-introduction)
|
||||
- [I. Initial Config](#i-initial-config)
|
||||
- [II. Tidy Config](#ii-tidy-config)
|
||||
- [III. Compiling Proto files](#iii-compiling-proto-files)
|
||||
- [Examples](#examples)
|
||||
- [Config File](#config-file)
|
||||
- [Definition](#definition)
|
||||
- [Matching patterns and working directory](#matching-patterns-and-working-directory)
|
||||
- [Multi-config](#multi-config)
|
||||
- [PostAction](#postaction)
|
||||
- [1. copy](#1-copy)
|
||||
- [2. move](#2-move)
|
||||
- [3. remove](#3-remove)
|
||||
- [4. replace](#4-replace)
|
||||
|
||||
|
||||
## Features
|
||||
|
||||
1. realize one-click installation and multi-version management of protoc.
|
||||
2. realize one-click installation and multi-version management of protoc related plugins (such as protoc-gen-go).
|
||||
3. manage the compilation of proto through config file instead of shell script to improve readability and compatibility.
|
||||
4. bootstrap generation of config files, cross-platform compatibility, a config can be compiled in multiple platforms with one click.
|
||||
5. support batch and recursive compilation of proto files to improve efficiency.
|
||||
6. cross-platform support PostAction, you can perform some routine operations (such as replacing "omitempty" in all generated files) after the compilation.
|
||||
7. support PostShell, execute specific shell scripts after the compilation.
|
||||
|
||||
## Installation and Dependencies
|
||||
|
||||
1. The current version of `PowerProto` relies on `go` and `git` (in the future it may use CDN to pull built binaries directly), please make sure the runtime environment contains these two commands.
|
||||
2. `protoc` download source is Github, `PowerProto` respects `HTTP_PROXY`, `HTTPS_PROXY` environment variables when downloading `protoc`, if you encounter network problems, please configure your own proxy.
|
||||
3. When querying the version list of `protoc`, `git ls-remote` is used for `github.com`, if you encounter network problems, please configure the proxy for `git` by yourself.
|
||||
4. In the current version, downloading and querying plugin versions rely on the `go` command, so if you encounter network problems, please configure the `GOPROXY` environment variable yourself.
|
||||
5. By default, `user directory/.powerproto` is used as the installation directory, which is used to place the downloaded plug-ins and global config.
|
||||
6. If you think the name `powerproto` is too long, you can `alias` it into a simpler name to improve the input efficiency, for example, no one will mind if you call it `pp`.
|
||||
|
||||
|
||||
### I. Installation via Go
|
||||
|
||||
Installation can be performed by executing the following command directly:
|
||||
|
||||
```
|
||||
go install github.com/storyicon/powerproto/cmd/powerproto
|
||||
```
|
||||
|
||||
### II. out-of-the-box version
|
||||
|
||||
You can download the out-of-the-box version via the `Github Release Page`.
|
||||
|
||||
|
||||
## Command Introduction
|
||||
|
||||
You can view help with `powerproto -h`, e.g.
|
||||
|
||||
```
|
||||
powerproto -h
|
||||
powerproto init -h
|
||||
powerproto tidy -h
|
||||
powerproto build -h
|
||||
```
|
||||
|
||||
It has the advantage that the documentation on the command line is always consistent with your binary version.
|
||||
|
||||
### I. Initial Config
|
||||
|
||||
The config can be initialized with the following command.
|
||||
|
||||
```
|
||||
powerproto init
|
||||
```
|
||||
|
||||
### II. Tidy Config
|
||||
|
||||
The config can be tidied with the following command.
|
||||
|
||||
```
|
||||
powerproto tidy
|
||||
```
|
||||
|
||||
It will search for a config file named `powerproto.yaml` from the current directory to the parent directory, and will read and tidy the config.
|
||||
|
||||
You can also specify which config file to tidy.
|
||||
|
||||
```
|
||||
powerproto tidy [the path of proto file]
|
||||
```
|
||||
|
||||
Tidy the config consists of two main operations:
|
||||
|
||||
1. replacing the latest in the version with the real latest version number by querying.
|
||||
2. install all dependencies defined in the config file.
|
||||
|
||||
|
||||
### III. Compiling Proto files
|
||||
|
||||
The Proto file can be compiled with the following command.
|
||||
|
||||
```
|
||||
// Compile the specified proto file
|
||||
powerproto build xxxx.proto
|
||||
|
||||
// Compile all the proto files in the current directory
|
||||
powerproto build .
|
||||
|
||||
// Compile all proto files in the current directory recursively, including subfolders.
|
||||
powerproto build -r .
|
||||
```
|
||||
|
||||
The execution logic is that for each proto file, the `powerproto.yaml` config file will be searched from the directory where the proto file is located to the ancestor directory:
|
||||
|
||||
1. For the found config file, match it with the `scope` in it and use it if it matches.
|
||||
2. Check and install the dependencies declared in the config file.
|
||||
3. Compile the proto file according to the `plugins`, `protoc`, `options`, `importPaths` and other configs in the config file。 After all the proto files are compiled, if you specify the `-p` argument, `PostAction` and `PostShell` will also be executed.
|
||||
|
||||
Note: The default `working directory` of `PowerProto` is the directory where the `proto file` matches to the config file, it is equivalent to the directory where you execute the `protoc` command. You can change it via `protocWorkDir` in the config file.
|
||||
|
||||
## Examples
|
||||
|
||||
For example, you have the following file structure in the `/mnt/data/hello` directory:
|
||||
|
||||
```
|
||||
$ pwd
|
||||
/mnt/data/hello
|
||||
|
||||
$ tree
|
||||
./apis
|
||||
└── hello.proto
|
||||
powerproto.yaml
|
||||
```
|
||||
|
||||
The contents of the `powerproto.yaml` file (you can easily generate the config file with the `powerproto init` command) are:
|
||||
|
||||
```
|
||||
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
|
||||
options:
|
||||
- --go_out=.
|
||||
- --go_opt=paths=source_relative
|
||||
- --go-grpc_out=.
|
||||
- --go-grpc_opt=paths=source_relative
|
||||
importPaths:
|
||||
- .
|
||||
- $GOPATH
|
||||
- $POWERPROTO_INCLUDE
|
||||
postActions: []
|
||||
postShell: ""
|
||||
```
|
||||
|
||||
Execute in any directory:
|
||||
|
||||
```
|
||||
powerproto build -r /mnt/data/hello/apis
|
||||
```
|
||||
|
||||
You can get the compiled file:
|
||||
|
||||
```
|
||||
$ pwd
|
||||
/mnt/data/hello
|
||||
|
||||
$ tree
|
||||
./apis
|
||||
├── hello.pb.go
|
||||
├── hello.proto
|
||||
└── hello_grpc.pb.go
|
||||
powerproto.yaml
|
||||
```
|
||||
|
||||
It is equivalent to if you were in the directory where `powerproto.yaml` is located and executed:
|
||||
|
||||
```shell script
|
||||
$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 \
|
||||
--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
|
||||
```
|
||||
|
||||
## Config File
|
||||
|
||||
The config file is used to describe the versions of various dependencies and parameters when compiling the proto file.
|
||||
|
||||
It can be easily initialized with `powerproto init`.
|
||||
|
||||
### Definition
|
||||
|
||||
Take the following config file as an example:
|
||||
|
||||
```yaml
|
||||
# required. scopes is used to define scopes.
|
||||
# i.e. which directories in the project the current config item is valid for
|
||||
scopes:
|
||||
- ./
|
||||
# required. the version of protoc.
|
||||
# you can fill in the 'latest', will be automatically converted to the latest version
|
||||
protoc: 3.17.3
|
||||
# optional. The working directory for executing the protoc command,
|
||||
# the default is the directory where the config file is located.
|
||||
# support mixed environment variables in path, such as $GOPATH
|
||||
protocWorkDir: ""
|
||||
# required. it is used to describe which plug-ins are required for compilation
|
||||
plugins:
|
||||
# the name, path, and version number of the plugin.
|
||||
# the address of the plugin must be in path@version format,
|
||||
# and version can be filled with 'latest', which will be automatically converted to the latest version.
|
||||
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
|
||||
# required. defines the parameters of protoc when compiling proto files
|
||||
options:
|
||||
- --go_out=paths=source_relative:.
|
||||
- --go-json_out=.
|
||||
- --deepcopy_out=source_relative:.
|
||||
- --grpc-gateway_out=.
|
||||
- --go-grpc_out=paths=source_relative:.
|
||||
# required. defines the path of the proto dependency, which will be converted to the --proto_path (-I) parameter.
|
||||
# support mixed environment variables, such as $GOPATH/include.
|
||||
# $POWERPROTO_INCLUDE is a special variable that refers to $POWERPROTO_HOME/include, which contains the public proto files provided by protoc by default.
|
||||
# "." is the folder where the config file is located.
|
||||
importPaths:
|
||||
- .
|
||||
- $GOPATH
|
||||
- $POWERPROTO_INCLUDE
|
||||
# optional. The operation is executed after compilation.
|
||||
# its working directory is the directory where the config file is located.
|
||||
# postActions is cross-platform compatible.
|
||||
# Note that the "-p" parameter must be appended to the "powerproto build" to allow execution of the postActions in the config file
|
||||
postActions: []
|
||||
# optional. The shell script that is executed after compilation.
|
||||
# its working directory is the directory where the config file is located.
|
||||
# postShell is not cross-platform compatible.
|
||||
# Note that the "-p" parameter must be appended to the "powerproto build" to allow execution of the postShell in the config file
|
||||
postShell: |
|
||||
// do something
|
||||
```
|
||||
|
||||
#### Matching patterns and working directory
|
||||
|
||||
When building the proto file, the `powerproto.yaml` config file will be searched from the directory where the proto file is located to the ancestor directory, match with the `scope` in.
|
||||
The first matched config item will be used for the compilation of this proto file.
|
||||
When PowerProto executes protoc (and also when it executes postActions and postShell), the default is to use the directory where the config file is located as the working directory. (working directory is equivalent to the directory where you execute the protoc command.)
|
||||
|
||||
#### Multi-config
|
||||
|
||||
A config file can be filled with multiple configs, which are separated by "---".
|
||||
|
||||
In the example below, the apis1 directory uses protoc-gen-go with v1.25.0, while the apis2 directory uses protoc-gen-go with v1.27.0.
|
||||
|
||||
```
|
||||
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
|
||||
options:
|
||||
- --go_out=.
|
||||
- --go_opt=paths=source_relative
|
||||
- --go-grpc_out=.
|
||||
- --go-grpc_opt=paths=source_relative
|
||||
importPaths:
|
||||
- .
|
||||
- $GOPATH
|
||||
- $POWERPROTO_INCLUDE
|
||||
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
|
||||
options:
|
||||
- --go_out=.
|
||||
- --go_opt=paths=source_relative
|
||||
- --go-grpc_out=.
|
||||
- --go-grpc_opt=paths=source_relative
|
||||
importPaths:
|
||||
- .
|
||||
- $GOPATH
|
||||
- $POWERPROTO_INCLUDE
|
||||
postActions: []
|
||||
postShell: ""
|
||||
```
|
||||
|
||||
|
||||
|
||||
### PostAction
|
||||
|
||||
PostAction allows to perform specific actions after all proto files have been compiled. In contrast to `PostShell`, it is cross-platform supported.
|
||||
For security reasons, the `PostAction` and `PostShell` defined in the config file will only be executed if the `-p` argument is appended to the execution of `powerproto build`.
|
||||
|
||||
|
||||
Currently, PostAction supports the following commands:
|
||||
|
||||
| Command | Description | Function Prototype |
|
||||
| ------- | ---------------------- | ----------------------------------------------------- |
|
||||
| copy | Copy file or folder | copy(src string, dest string) error |
|
||||
| move | Move file or folder | move(src string, dest string) error |
|
||||
| remove | Delete file or folder | remove(path ...string) error |
|
||||
| replace | Batch replacement of strings in files | replace(pattern string, from string, to string) error |
|
||||
|
||||
#### 1. copy
|
||||
|
||||
For copying files or folders, the function prototype is:
|
||||
|
||||
```
|
||||
copy(src string, dest string) error
|
||||
```
|
||||
|
||||
For security and config compatibility, only relative paths are allowed in the parameters.
|
||||
|
||||
If the target folder already exists, it will be merged.
|
||||
|
||||
The following example will copy 'a' from the directory where the config file is located to 'b'.
|
||||
|
||||
```yaml
|
||||
postActions:
|
||||
- name: copy
|
||||
args:
|
||||
- ./a
|
||||
- ./b
|
||||
```
|
||||
|
||||
#### 2. move
|
||||
|
||||
For moving files or folders, the function prototype is:
|
||||
|
||||
```
|
||||
move(src string, dest string) error
|
||||
```
|
||||
|
||||
For security and config compatibility, only relative paths are allowed in the parameters.
|
||||
|
||||
If the target folder already exists, it will be merged.
|
||||
|
||||
The following example will move 'a' in the directory where the config file is located to 'b'.
|
||||
|
||||
```yaml
|
||||
postActions:
|
||||
- name: move
|
||||
args:
|
||||
- ./a
|
||||
- ./b
|
||||
```
|
||||
|
||||
#### 3. remove
|
||||
|
||||
For deleting files or folders, the function prototype is:
|
||||
|
||||
```
|
||||
remove(path ...string) error
|
||||
```
|
||||
|
||||
For security and config compatibility, only relative paths are allowed in the parameters.
|
||||
|
||||
The following example will remove 'a', 'b' and 'c' from the directory where the config file is located:
|
||||
|
||||
```yaml
|
||||
postActions:
|
||||
- name: remove
|
||||
args:
|
||||
- ./a
|
||||
- ./b
|
||||
- ./c
|
||||
```
|
||||
|
||||
#### 4. replace
|
||||
|
||||
Used for batch replacement of strings in files. Its function prototype is:
|
||||
|
||||
```
|
||||
replace(pattern string, from string, to string) error
|
||||
```
|
||||
|
||||
* `pattern` is a relative path that supports wildcard characters.
|
||||
* `from` is the string to be replaced.
|
||||
* `to` is the string to replace with.
|
||||
|
||||
The following example will replace `,omitempty` with the empty string in all go files in the apis directory and its subdirectories:
|
||||
|
||||
```
|
||||
postActions:
|
||||
- name: replace
|
||||
args:
|
||||
- ./apis/**/*.go
|
||||
- ',omitempty'
|
||||
- ""
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
430
README_CN.md
Normal file
430
README_CN.md
Normal file
|
|
@ -0,0 +1,430 @@
|
|||
# PowerProto
|
||||
|
||||
[](https://goreportcard.com/report/github.com/storyicon/powerproto)   [](https://godoc.org/github.com/storyicon/powerproto)
|
||||
|
||||
**中文** | [English](README_CN.md)
|
||||
|
||||

|
||||
|
||||
PowerProto主要用于解决下面三个问题:
|
||||
|
||||
1. 降低gRPC的使用门槛与使用成本。
|
||||
2. 解决protoc以及其相关插件(比如protoc-gen-go、protoc-gen-grpc-gateway)的版本控制问题。
|
||||
3. 高效管理proto的编译,实现多平台兼容、一键安装与编译。
|
||||
|
||||
|
||||
- [PowerProto](#powerproto)
|
||||
- [功能](#功能)
|
||||
- [安装与依赖](#安装与依赖)
|
||||
- [一、通过Go进行安装](#一通过go进行安装)
|
||||
- [二、开箱即用版本](#二开箱即用版本)
|
||||
- [命令介绍](#命令介绍)
|
||||
- [一、初始化配置](#一初始化配置)
|
||||
- [二、整理配置](#二整理配置)
|
||||
- [三、编译Proto文件](#三编译proto文件)
|
||||
- [示例](#示例)
|
||||
- [配置文件](#配置文件)
|
||||
- [解释](#解释)
|
||||
- [匹配模式与工作目录](#匹配模式与工作目录)
|
||||
- [多配置组合](#多配置组合)
|
||||
- [PostAction](#postaction)
|
||||
- [1. copy](#1-copy)
|
||||
- [2. move](#2-move)
|
||||
- [3. remove](#3-remove)
|
||||
- [4. replace](#4-replace)
|
||||
|
||||
|
||||
## 功能
|
||||
|
||||
1. 实现protoc的一键安装与多版本管理。
|
||||
2. 实现protoc相关插件(比如protoc-gen-go)的一键安装与多版本管理。
|
||||
3. 通过配置文件管理proto的编译,而非shell脚本,提高可读性与兼容性。
|
||||
4. 引导式生成配置文件,跨平台兼容,一份配置在多个平台均可以实现一键编译。
|
||||
5. 支持批量、递归编译proto文件,提高效率。
|
||||
6. 跨平台支持PostAction,可以在编译完成之后执行一些常规操作(比如替换掉所有生成文件中的"omitempty")。
|
||||
7. 支持PostShell,在编译完成之后执行特定的shell脚本。
|
||||
|
||||
## 安装与依赖
|
||||
|
||||
1. 目前版本的 `PowerProto` 依赖 `go` 以及 `git`(未来可能会直接使用CDN拉取构建好的二进制),请确保运行环境中包含这两个命令。
|
||||
2. `protoc`的下载源是Github,`PowerProto`在下载`protoc`时尊重 `HTTP_PROXY`、`HTTPS_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
|
||||
```
|
||||
|
||||
它的好处是命令行中的文档永远和你的二进制版本保持一致。而Github上的文档可能会一直是对应最新的二进制。
|
||||
|
||||
### 一、初始化配置
|
||||
|
||||
可以通过下面的命令进行配置的初始化:
|
||||
|
||||
```
|
||||
powerproto init
|
||||
```
|
||||
|
||||
|
||||
|
||||
### 二、整理配置
|
||||
|
||||
可以通过下面的命令整理配置:
|
||||
|
||||
```
|
||||
powerproto tidy
|
||||
```
|
||||
|
||||
它将会从当前目录开始向父级目录搜索名为 `powerproto.yaml` 的配置文件,并对配置进行读取和整理。
|
||||
|
||||
你也可以指定整理哪个配置文件:
|
||||
|
||||
```
|
||||
powerproto tidy [the path of proto file]
|
||||
```
|
||||
|
||||
整理配置主要包含两个操作:
|
||||
|
||||
1. 通过查询,将版本中的latest替换为真实的最新版本号。
|
||||
2. 安装配置文件中定义的所有依赖。
|
||||
|
||||
|
||||
|
||||
### 三、编译Proto文件
|
||||
|
||||
可以通过下面的命令进行Proto文件的编译:
|
||||
|
||||
```
|
||||
// 编译指定的proto文件
|
||||
powerproto build xxxx.proto
|
||||
|
||||
// 编译当前目录下的所有proto文件
|
||||
powerproto build .
|
||||
|
||||
// 递归编译当前目录下的所有proto文件,包括子文件夹。
|
||||
powerproto build -r .
|
||||
```
|
||||
|
||||
其执行逻辑是,对于每一个proto文件,从其文件所在目录开始向父级目录寻找 `powerproto.yaml` 配置文件:
|
||||
|
||||
1. 对于找到的配置文件,与其中的`scope`进行匹配,如果匹配则采用。
|
||||
2. 检查并安装配置文件中声明的依赖。
|
||||
3. 根据配置文件中的`plugins`、`protoc`、`options`、`importPaths`等配置对proto文件进行编译。 当所有的proto文件都编译完成之后,如果你指定了 `-p` 参数,还会进行`PostAction`与`PostShell`的执行。
|
||||
|
||||
注意:`protoc`执行的工作目录默认是`proto文件`匹配到的配置文件所在的目录,它相当于你在配置文件所在目录执行protoc命令。你可以通过配置文件中的 `protocWorkDir` 来进行修改。
|
||||
|
||||
|
||||
|
||||
## 示例
|
||||
|
||||
比如你在 `/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
|
||||
options:
|
||||
- --go_out=.
|
||||
- --go_opt=paths=source_relative
|
||||
- --go-grpc_out=.
|
||||
- --go-grpc_opt=paths=source_relative
|
||||
importPaths:
|
||||
- .
|
||||
- $GOPATH
|
||||
- $POWERPROTO_INCLUDE
|
||||
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 \
|
||||
--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`进行配置文件的初始化。
|
||||
|
||||
### 解释
|
||||
|
||||
以下面这份配置文件为例:
|
||||
|
||||
|
||||
```yaml
|
||||
# 必填,scopes 用于定义作用域,即当前配置项对项目中的哪些目录生效
|
||||
scopes:
|
||||
- ./
|
||||
# 必填,protoc的版本,可以填 latest,会自动转换成最新的版本
|
||||
protoc: 3.17.3
|
||||
# 选填,执行protoc命令的工作目录,默认是配置文件所在目录
|
||||
# 支持路径中混用环境变量,比如$GOPATH
|
||||
protocWorkDir: ""
|
||||
# 必填,代表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) 参数。
|
||||
# 支持混用环境变量,比如 $GOPATH/include。
|
||||
# $POWERPROTO_INCLUDE是一个特殊变量,指 $POWERPRTO/include,里面包含了protoc默认提供的公共proto 文件。
|
||||
# "." 是指配置文件所在文件夹。
|
||||
importPaths:
|
||||
- .
|
||||
- $GOPATH
|
||||
- $POWERPROTO_INCLUDE
|
||||
# 选填,构建完成之后执行的操作,工作目录是配置文件所在目录
|
||||
# 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
|
||||
options:
|
||||
- --go_out=.
|
||||
- --go_opt=paths=source_relative
|
||||
- --go-grpc_out=.
|
||||
- --go-grpc_opt=paths=source_relative
|
||||
importPaths:
|
||||
- .
|
||||
- $GOPATH
|
||||
- $POWERPROTO_INCLUDE
|
||||
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
|
||||
options:
|
||||
- --go_out=.
|
||||
- --go_opt=paths=source_relative
|
||||
- --go-grpc_out=.
|
||||
- --go-grpc_opt=paths=source_relative
|
||||
importPaths:
|
||||
- .
|
||||
- $GOPATH
|
||||
- $POWERPROTO_INCLUDE
|
||||
postActions: []
|
||||
postShell: ""
|
||||
```
|
||||
|
||||
|
||||
### PostAction
|
||||
|
||||
PostAction允许在所有的proto文件都编译完成之后,执行特定的操作。与`PostShell`相比,它是跨平台支持的。
|
||||
|
||||
为了安全起见,只有在执行 `powerproto build`时附加上 `-p` 参数,才会执行配置文件中定义的`PostAction`与`PostShell`。
|
||||
|
||||
目前,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:
|
||||
|
||||
```yaml
|
||||
postActions:
|
||||
- name: copy
|
||||
args:
|
||||
- ./a
|
||||
- ./b
|
||||
```
|
||||
|
||||
#### 2. move
|
||||
|
||||
用于移动文件或文件夹,其函数原型为:
|
||||
|
||||
```
|
||||
move(src string, dest string) error
|
||||
```
|
||||
|
||||
为了安全以及配置的兼容性,参数中只允许填写相对路径。
|
||||
|
||||
如果目标文件夹已经存在,将会合并。
|
||||
|
||||
下面的例子将会把配置文件所在目录下的a移动到b:
|
||||
|
||||
```yaml
|
||||
postActions:
|
||||
- name: move
|
||||
args:
|
||||
- ./a
|
||||
- ./b
|
||||
```
|
||||
|
||||
#### 3. remove
|
||||
|
||||
用于删除文件或文件夹,其函数原型为:
|
||||
|
||||
```
|
||||
remove(path ...string) error
|
||||
```
|
||||
|
||||
为了安全以及配置的兼容性,参数中只允许填写相对路径。
|
||||
|
||||
下面的例子将会删除配置文件所在目录下的a、b、c:
|
||||
|
||||
```yaml
|
||||
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'
|
||||
- ""
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
60
cmd/powerproto/main.go
Normal file
60
cmd/powerproto/main.go
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
// Copyright 2021 storyicon@foxmail.com
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
cmdbuild "github.com/storyicon/powerproto/cmd/powerproto/subcommands/build"
|
||||
cmdenv "github.com/storyicon/powerproto/cmd/powerproto/subcommands/env"
|
||||
cmdinit "github.com/storyicon/powerproto/cmd/powerproto/subcommands/init"
|
||||
cmdtidy "github.com/storyicon/powerproto/cmd/powerproto/subcommands/tidy"
|
||||
"github.com/storyicon/powerproto/pkg/util/logger"
|
||||
)
|
||||
|
||||
// Version is set via build flag -ldflags -X main.Version
|
||||
var (
|
||||
Version string
|
||||
Branch string
|
||||
Revision string
|
||||
BuildDate string
|
||||
)
|
||||
|
||||
var log = logger.NewDefault("command")
|
||||
|
||||
// GetRootCommand is used to get root command
|
||||
func GetRootCommand() *cobra.Command {
|
||||
return &cobra.Command{
|
||||
Use: "[powerproto]",
|
||||
Version: fmt.Sprintf("%s, branch: %s, revision: %s, buildDate: %s", Version, Branch, Revision, BuildDate),
|
||||
Short: "powerproto is used to build proto files and version control of protoc and related plug-ins",
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
_ = cmd.Help()
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
cmdRoot := GetRootCommand()
|
||||
cmdRoot.AddCommand(
|
||||
cmdbuild.CommandBuild(log),
|
||||
cmdinit.CommandInit(log),
|
||||
cmdtidy.CommandTidy(log),
|
||||
cmdenv.CommandEnv(log),
|
||||
)
|
||||
cmdRoot.Execute()
|
||||
}
|
||||
117
cmd/powerproto/subcommands/build/command.go
Normal file
117
cmd/powerproto/subcommands/build/command.go
Normal file
|
|
@ -0,0 +1,117 @@
|
|||
// Copyright 2021 storyicon@foxmail.com
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package build
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/storyicon/powerproto/pkg/bootstraps"
|
||||
"github.com/storyicon/powerproto/pkg/util"
|
||||
"github.com/storyicon/powerproto/pkg/util/command"
|
||||
"github.com/storyicon/powerproto/pkg/util/logger"
|
||||
)
|
||||
|
||||
const description = `
|
||||
Examples:
|
||||
compile specific proto file
|
||||
powerproto build [proto file]
|
||||
|
||||
compile the proto file in the folder, excluding sub folders:
|
||||
powerproto build [dir]
|
||||
|
||||
compile all proto files in the folder recursively, including sub folders:
|
||||
powerproto build -r [dir]
|
||||
|
||||
compile proto files and execute the post actions/shells:
|
||||
powerproto build -r -a [dir]
|
||||
`
|
||||
|
||||
// compile proto files
|
||||
// powerproto build -r .
|
||||
// powerproto build .
|
||||
// powerproto build xxxxx.proto
|
||||
func CommandBuild(log logger.Logger) *cobra.Command {
|
||||
var recursive bool
|
||||
// todo: this feature is still under development
|
||||
var dryRun bool
|
||||
var postScriptEnabled bool
|
||||
cmd := &cobra.Command{
|
||||
Use: "build [dir|proto file]",
|
||||
Short: "compile proto files",
|
||||
Long: strings.TrimSpace(description),
|
||||
Args: cobra.ExactArgs(1),
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
ctx := cmd.Context()
|
||||
if dryRun {
|
||||
ctx = command.WithDryRun(ctx)
|
||||
}
|
||||
if !postScriptEnabled {
|
||||
ctx = command.WithDisableAction(ctx)
|
||||
}
|
||||
|
||||
target, err := filepath.Abs(args[0])
|
||||
if err != nil {
|
||||
log.LogFatal(nil, "failed to abs target path: %s", err)
|
||||
}
|
||||
fileInfo, err := os.Stat(target)
|
||||
if err != nil {
|
||||
log.LogFatal(map[string]interface{}{
|
||||
"target": target,
|
||||
}, "failed to stat target: %s", err)
|
||||
}
|
||||
|
||||
var targets []string
|
||||
if fileInfo.IsDir() {
|
||||
log.LogInfo(nil, "search proto files...")
|
||||
if recursive {
|
||||
targets, err = util.GetFilesWithExtRecursively(target, ".proto")
|
||||
if err != nil {
|
||||
log.LogFatal(nil, "failed to walk directory: %s", err)
|
||||
}
|
||||
} else {
|
||||
targets, err = util.GetFilesWithExt(target, ".proto")
|
||||
if err != nil {
|
||||
log.LogFatal(nil, "failed to walk directory: %s", err)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
targets = append(targets, target)
|
||||
}
|
||||
|
||||
if len(targets) == 0 {
|
||||
log.LogWarn(nil, "no file to compile")
|
||||
return
|
||||
}
|
||||
if err := bootstraps.StepTidyConfig(ctx, targets); err != nil {
|
||||
log.LogFatal(nil, "failed to tidy config: %+v", err)
|
||||
return
|
||||
}
|
||||
|
||||
if err := bootstraps.Compile(ctx, targets); err != nil {
|
||||
log.LogFatal(nil, "failed to compile: %+v", err)
|
||||
}
|
||||
|
||||
log.LogInfo(nil, "succeed! you are ready to go :)")
|
||||
},
|
||||
}
|
||||
flags := cmd.PersistentFlags()
|
||||
flags.BoolVarP(&recursive, "recursive", "r", recursive, "whether to recursively traverse all child folders")
|
||||
flags.BoolVarP(&postScriptEnabled, "postScriptEnabled", "p", postScriptEnabled, "when this flag is attached, it will allow the execution of postActions and postShell")
|
||||
return cmd
|
||||
}
|
||||
57
cmd/powerproto/subcommands/env/command.go
vendored
Normal file
57
cmd/powerproto/subcommands/env/command.go
vendored
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
// Copyright 2021 storyicon@foxmail.com
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package env
|
||||
|
||||
import (
|
||||
"os"
|
||||
"os/exec"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/storyicon/powerproto/pkg/consts"
|
||||
"github.com/storyicon/powerproto/pkg/util/logger"
|
||||
)
|
||||
|
||||
// Print environment variables related to program operation
|
||||
func CommandEnv(log logger.Logger) *cobra.Command {
|
||||
return &cobra.Command{
|
||||
Use: "env",
|
||||
Short: "list the environments and binary files",
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
log.LogInfo(nil, "[ENVIRONMENT]")
|
||||
for _, key := range []string{
|
||||
consts.EnvHomeDir,
|
||||
"HTTP_PROXY",
|
||||
"HTTPS_PROXY",
|
||||
"GOPROXY",
|
||||
} {
|
||||
log.LogInfo(nil, "%s=%s", key, os.Getenv(key))
|
||||
}
|
||||
|
||||
log.LogInfo(nil, "[BIN]")
|
||||
for _, key := range []string {
|
||||
"go",
|
||||
"git",
|
||||
} {
|
||||
path, err := exec.LookPath(key)
|
||||
if err != nil {
|
||||
log.LogError(nil, "failed to find: %s", key)
|
||||
continue
|
||||
}
|
||||
log.LogInfo(nil, "%s=%s", key, path)
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
114
cmd/powerproto/subcommands/init/command.go
Normal file
114
cmd/powerproto/subcommands/init/command.go
Normal file
|
|
@ -0,0 +1,114 @@
|
|||
// Copyright 2021 storyicon@foxmail.com
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package build
|
||||
|
||||
import (
|
||||
"github.com/AlecAivazis/survey/v2"
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/storyicon/powerproto/pkg/configs"
|
||||
"github.com/storyicon/powerproto/pkg/consts"
|
||||
"github.com/storyicon/powerproto/pkg/util"
|
||||
"github.com/storyicon/powerproto/pkg/util/logger"
|
||||
)
|
||||
|
||||
// UserPreference defines the model of user preference
|
||||
type UserPreference struct {
|
||||
Plugins []string `survey:"plugins"`
|
||||
}
|
||||
|
||||
// GetUserPreference is used to get user preference
|
||||
func GetUserPreference() (*UserPreference, error) {
|
||||
var preference UserPreference
|
||||
err := survey.Ask([]*survey.Question{
|
||||
{
|
||||
Name: "plugins",
|
||||
Prompt: &survey.MultiSelect{
|
||||
Message: "select plugins to use. Later, you can also manually add in the configuration file",
|
||||
Options: GetWellKnownPluginsOptionValues(),
|
||||
},
|
||||
},
|
||||
}, &preference)
|
||||
return &preference, err
|
||||
}
|
||||
|
||||
// GetDefaultConfig is used to get default config
|
||||
func GetDefaultConfig() *configs.Config {
|
||||
return &configs.Config{
|
||||
Scopes: []string{
|
||||
"./",
|
||||
},
|
||||
Protoc: "latest",
|
||||
Plugins: map[string]string{
|
||||
"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",
|
||||
},
|
||||
Options: []string{
|
||||
"--go_out=.",
|
||||
"--go_opt=paths=source_relative",
|
||||
"--go-grpc_out=.",
|
||||
"--go-grpc_opt=paths=source_relative",
|
||||
},
|
||||
ImportPaths: []string{
|
||||
".",
|
||||
"$GOPATH",
|
||||
"$POWERPROTO_INCLUDE",
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// CommandInit is used to initialize the configuration
|
||||
// file in the current directory
|
||||
func CommandInit(log logger.Logger) *cobra.Command {
|
||||
return &cobra.Command{
|
||||
Use: "init",
|
||||
Short: "init a config file in current directory",
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
exists, err := util.IsFileExists(consts.ConfigFileName)
|
||||
if err != nil {
|
||||
log.LogError(nil, err.Error())
|
||||
return
|
||||
}
|
||||
if exists {
|
||||
log.LogInfo(nil, "config file already exists in this directory")
|
||||
return
|
||||
}
|
||||
|
||||
preference, err := GetUserPreference()
|
||||
if err != nil {
|
||||
log.LogError(nil, err.Error())
|
||||
return
|
||||
}
|
||||
config := GetDefaultConfig()
|
||||
if len(preference.Plugins) != 0 {
|
||||
var compileOptions []string
|
||||
plugins := map[string]string{}
|
||||
for _, val := range preference.Plugins {
|
||||
plugin, ok := GetPluginFromOptionsValue(val)
|
||||
if ok {
|
||||
plugins[plugin.Name] = plugin.Pkg
|
||||
compileOptions = append(compileOptions, plugin.Options...)
|
||||
}
|
||||
}
|
||||
config.Plugins = plugins
|
||||
config.Options = compileOptions
|
||||
}
|
||||
if err := configs.SaveConfigs(consts.ConfigFileName, config); err != nil {
|
||||
log.LogFatal(nil, "failed to save config: %s", err)
|
||||
}
|
||||
log.LogInfo(nil, "succeed! You can use `powerproto tidy` to tidy this config file")
|
||||
},
|
||||
}
|
||||
}
|
||||
95
cmd/powerproto/subcommands/init/plugins.go
Normal file
95
cmd/powerproto/subcommands/init/plugins.go
Normal file
|
|
@ -0,0 +1,95 @@
|
|||
// Copyright 2021 storyicon@foxmail.com
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package build
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// Plugin defines the plugin options
|
||||
type Plugin struct {
|
||||
Name string
|
||||
Pkg string
|
||||
Options []string
|
||||
}
|
||||
|
||||
// String implements the standard string interface
|
||||
func (options *Plugin) String() string {
|
||||
return fmt.Sprintf("%s: %s", options.Name, options.Pkg)
|
||||
}
|
||||
|
||||
// GetWellKnownPlugins is used to get well known plugins
|
||||
func GetWellKnownPlugins() []*Plugin {
|
||||
return []*Plugin{
|
||||
{
|
||||
Name: "protoc-gen-go",
|
||||
Pkg: "google.golang.org/protobuf/cmd/protoc-gen-go@latest",
|
||||
Options: []string{
|
||||
"--go_out=.",
|
||||
"--go_opt=paths=source_relative",
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "protoc-gen-go-grpc",
|
||||
Pkg: "google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest",
|
||||
Options: []string{
|
||||
"--go-grpc_out=.",
|
||||
"--go-grpc_opt=paths=source_relative",
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "protoc-gen-grpc-gateway",
|
||||
Pkg: "github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-grpc-gateway@latest",
|
||||
Options: []string{
|
||||
"--grpc-gateway_out=.",
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "protoc-gen-deepcopy",
|
||||
Pkg: "istio.io/tools/cmd/protoc-gen-deepcopy@latest",
|
||||
Options: []string{
|
||||
"--deepcopy_out=source_relative:.",
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "protoc-gen-go-json",
|
||||
Pkg: "github.com/mitchellh/protoc-gen-go-json@latest",
|
||||
Options: []string{
|
||||
"--go-json_out=.",
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// GetPluginFromOptionsValue is used to get plugin by option value
|
||||
func GetPluginFromOptionsValue(val string) (*Plugin, bool) {
|
||||
plugins := GetWellKnownPlugins()
|
||||
for _, plugin := range plugins {
|
||||
if plugin.String() == val {
|
||||
return plugin, true
|
||||
}
|
||||
}
|
||||
return nil, false
|
||||
}
|
||||
|
||||
// GetWellKnownPluginsOptionValues is used to get option values of well known plugins
|
||||
func GetWellKnownPluginsOptionValues() []string {
|
||||
plugins := GetWellKnownPlugins()
|
||||
packages := make([]string, 0, len(plugins))
|
||||
for _, plugin := range plugins {
|
||||
packages = append(packages, plugin.String())
|
||||
}
|
||||
return packages
|
||||
}
|
||||
108
cmd/powerproto/subcommands/tidy/command.go
Normal file
108
cmd/powerproto/subcommands/tidy/command.go
Normal file
|
|
@ -0,0 +1,108 @@
|
|||
// Copyright 2021 storyicon@foxmail.com
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package tidy
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/storyicon/powerproto/pkg/bootstraps"
|
||||
"github.com/storyicon/powerproto/pkg/component/pluginmanager"
|
||||
"github.com/storyicon/powerproto/pkg/configs"
|
||||
"github.com/storyicon/powerproto/pkg/util"
|
||||
"github.com/storyicon/powerproto/pkg/util/logger"
|
||||
"github.com/storyicon/powerproto/pkg/util/progressbar"
|
||||
)
|
||||
|
||||
func tidy(ctx context.Context,
|
||||
pluginManager pluginmanager.PluginManager,
|
||||
configFilePath string) error {
|
||||
progress := progressbar.GetProgressBar(1)
|
||||
progress.SetPrefix("tidy config")
|
||||
err := bootstraps.StepTidyConfigFile(ctx, pluginManager, progress, configFilePath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
progress.Incr()
|
||||
progress.Wait()
|
||||
configItems, err := configs.LoadConfigItems(configFilePath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := bootstraps.StepInstallProtoc(ctx, pluginManager, configItems); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := bootstraps.StepInstallPlugins(ctx, pluginManager, configItems); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// By default, clean the powerproto.yaml of the current directory and all parent directories
|
||||
// You can also explicitly specify the configuration file to clean up
|
||||
func CommandTidy(log logger.Logger) *cobra.Command {
|
||||
return &cobra.Command{
|
||||
Use: "tidy [config file]",
|
||||
Short: "tidy the config file. It will replace the version number and install the protoc and proto plugins that declared in the config file",
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
var targets []string
|
||||
if len(args) != 0 {
|
||||
for _, arg := range args {
|
||||
dir, _ := filepath.Abs(arg)
|
||||
targets = append(targets, dir)
|
||||
}
|
||||
} else {
|
||||
dir, err := os.Getwd()
|
||||
if err != nil {
|
||||
log.LogFatal(nil, "failed to get current dir: %s", err)
|
||||
}
|
||||
targets = configs.ListConfigPaths(dir)
|
||||
}
|
||||
pluginManager, err := pluginmanager.NewPluginManager(pluginmanager.NewConfig(), log)
|
||||
if err != nil {
|
||||
log.LogFatal(nil, "failed to create plugin manager: %s", err)
|
||||
}
|
||||
configMap := map[string]struct{}{}
|
||||
for _, path := range targets {
|
||||
exists, err := util.IsFileExists(path)
|
||||
if err != nil {
|
||||
log.LogFatal(map[string]interface{}{
|
||||
"path": path,
|
||||
"err": err,
|
||||
}, "failed to tidy config")
|
||||
}
|
||||
if !exists {
|
||||
continue
|
||||
}
|
||||
log.LogInfo(nil, "tidy %s", path)
|
||||
if err := tidy(cmd.Context(), pluginManager, path); err != nil {
|
||||
log.LogFatal(map[string]interface{}{
|
||||
"path": path,
|
||||
"err": err,
|
||||
}, "failed to tidy config")
|
||||
}
|
||||
configMap[path] = struct{}{}
|
||||
}
|
||||
log.LogInfo(nil, "these following config files were tidied:")
|
||||
for path := range configMap {
|
||||
log.LogInfo(nil, " %s", path)
|
||||
}
|
||||
log.LogInfo(nil, "\r\nsucceeded, you are ready to go :)")
|
||||
},
|
||||
}
|
||||
}
|
||||
BIN
docs/images/exmaple.gif
Normal file
BIN
docs/images/exmaple.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.3 MiB |
34
go.mod
Normal file
34
go.mod
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
module github.com/storyicon/powerproto
|
||||
|
||||
go 1.16
|
||||
|
||||
require (
|
||||
github.com/AlecAivazis/survey/v2 v2.2.14
|
||||
github.com/bmatcuk/doublestar v1.3.4
|
||||
github.com/dsnet/compress v0.0.1 // indirect
|
||||
github.com/fatih/color v1.12.0
|
||||
github.com/frankban/quicktest v1.13.0 // indirect
|
||||
github.com/golang/snappy v0.0.4 // indirect
|
||||
github.com/hashicorp/go-multierror v1.0.0
|
||||
github.com/json-iterator/go v1.1.11
|
||||
github.com/mattn/go-isatty v0.0.13 // indirect
|
||||
github.com/mholt/archiver v3.1.1+incompatible
|
||||
github.com/nwaples/rardecode v1.1.0 // indirect
|
||||
github.com/onsi/ginkgo v1.16.4
|
||||
github.com/onsi/gomega v1.14.0
|
||||
github.com/otiai10/copy v1.6.0
|
||||
github.com/pierrec/lz4 v2.6.1+incompatible // indirect
|
||||
github.com/pkg/errors v0.9.1
|
||||
github.com/prometheus/client_golang v1.11.0
|
||||
github.com/rs/zerolog v1.23.0
|
||||
github.com/spf13/cobra v1.2.1
|
||||
github.com/spf13/pflag v1.0.5
|
||||
github.com/ulikunitz/xz v0.5.10 // indirect
|
||||
github.com/vbauerster/mpb/v7 v7.0.3
|
||||
github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 // indirect
|
||||
golang.org/x/mod v0.4.2
|
||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c // indirect
|
||||
golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b
|
||||
)
|
||||
763
go.sum
Normal file
763
go.sum
Normal file
|
|
@ -0,0 +1,763 @@
|
|||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
|
||||
cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=
|
||||
cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
|
||||
cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=
|
||||
cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=
|
||||
cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To=
|
||||
cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4=
|
||||
cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M=
|
||||
cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc=
|
||||
cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk=
|
||||
cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs=
|
||||
cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc=
|
||||
cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY=
|
||||
cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI=
|
||||
cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk=
|
||||
cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg=
|
||||
cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8=
|
||||
cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0=
|
||||
cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
|
||||
cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
|
||||
cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=
|
||||
cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg=
|
||||
cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc=
|
||||
cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ=
|
||||
cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
|
||||
cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk=
|
||||
cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk=
|
||||
cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
|
||||
cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=
|
||||
cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA=
|
||||
cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU=
|
||||
cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
|
||||
cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos=
|
||||
cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk=
|
||||
cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=
|
||||
cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
|
||||
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
|
||||
github.com/AlecAivazis/survey/v2 v2.2.14 h1:aTYTaCh1KLd+YWilkeJ65Ph78g48NVQ3ay9xmaNIyhk=
|
||||
github.com/AlecAivazis/survey/v2 v2.2.14/go.mod h1:TH2kPCDU3Kqq7pLbnCWwZXDBjnhZtmsCle5EiYDJ2fg=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||
github.com/Netflix/go-expect v0.0.0-20180615182759-c93bf25de8e8 h1:xzYJEypr/85nBpB11F9br+3HUrpgb+fcm5iADzXXYEw=
|
||||
github.com/Netflix/go-expect v0.0.0-20180615182759-c93bf25de8e8/go.mod h1:oX5x61PbNXchhh0oikYAH+4Pcfw5LKv21+Jnpr6r6Pc=
|
||||
github.com/VividCortex/ewma v1.2.0 h1:f58SaIzcDXrSy3kWaHNvuJgJ3Nmz59Zji6XoJR/q1ow=
|
||||
github.com/VividCortex/ewma v1.2.0/go.mod h1:nz4BbCtbLyFDeC9SUHbtcT5644juEuWfUAUnGx7j5l4=
|
||||
github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d h1:licZJFw2RwpHMqeKTCYkitsPqHNxTmd4SNR5r94FGM8=
|
||||
github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d/go.mod h1:asat636LX7Bqt5lYEZ27JNDcqxfjdBQuJ/MM4CN/Lzo=
|
||||
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=
|
||||
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
|
||||
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
|
||||
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
|
||||
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
|
||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
|
||||
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
||||
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
||||
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
|
||||
github.com/bketelsen/crypt v0.0.4/go.mod h1:aI6NrJ0pMGgvZKL1iVgXLnfIFJtfV+bKCoqOes/6LfM=
|
||||
github.com/bmatcuk/doublestar v1.3.4 h1:gPypJ5xD31uhX6Tf54sDPUOBXTqKH4c9aPY66CyQrS0=
|
||||
github.com/bmatcuk/doublestar v1.3.4/go.mod h1:wiQtGV+rzVYxB7WIlirSN++5HPtPlXEo9MEoZQC/PmE=
|
||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||
github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY=
|
||||
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
|
||||
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
|
||||
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
||||
github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
||||
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
||||
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
||||
github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/dsnet/compress v0.0.1 h1:PlZu0n3Tuv04TzpfPbrnI0HW/YwodEXDS+oPKahKF0Q=
|
||||
github.com/dsnet/compress v0.0.1/go.mod h1:Aw8dCMJ7RioblQeTqt88akK31OvO8Dhf5JflhBbQEHo=
|
||||
github.com/dsnet/golib v0.0.0-20171103203638-1ea166775780/go.mod h1:Lj+Z9rebOhdfkVLjJ8T6VcRQv3SXugXy999NBtR9aFY=
|
||||
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
|
||||
github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po=
|
||||
github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
|
||||
github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
|
||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
||||
github.com/fatih/color v1.12.0 h1:mRhaKNwANqRgUBGKmnI5ZxEk7QXmjQeCcuYFMX2bfcc=
|
||||
github.com/fatih/color v1.12.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM=
|
||||
github.com/frankban/quicktest v1.13.0 h1:yNZif1OkDfNoDfb9zZa9aXIpejNR4F23Wely0c+Qdqk=
|
||||
github.com/frankban/quicktest v1.13.0/go.mod h1:qLE0fzW0VuyUAJgPU19zByoIr0HtCHN/r/VLSOOIySU=
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
|
||||
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||
github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY=
|
||||
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
|
||||
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
|
||||
github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
|
||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
|
||||
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
|
||||
github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
|
||||
github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
|
||||
github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
|
||||
github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
|
||||
github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
|
||||
github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
|
||||
github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk=
|
||||
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
|
||||
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
|
||||
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
|
||||
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
|
||||
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
|
||||
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
|
||||
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||
github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM=
|
||||
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
|
||||
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||
github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
|
||||
github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
|
||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
|
||||
github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
|
||||
github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
|
||||
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||
github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||
github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
|
||||
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
|
||||
github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q=
|
||||
github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=
|
||||
github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA=
|
||||
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
||||
github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
|
||||
github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
|
||||
github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=
|
||||
github.com/hashicorp/go-multierror v1.0.0 h1:iVjPR7a6H0tWELX5NxNe7bYopibicUzc7uPribsnS6o=
|
||||
github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
|
||||
github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU=
|
||||
github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU=
|
||||
github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
|
||||
github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||
github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||
github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90=
|
||||
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
||||
github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=
|
||||
github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ=
|
||||
github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I=
|
||||
github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=
|
||||
github.com/hinshun/vt10x v0.0.0-20180616224451-1954e6464174 h1:WlZsjVhE8Af9IcZDGgJGQpNflI3+MJSBhsgT5PCtzBQ=
|
||||
github.com/hinshun/vt10x v0.0.0-20180616224451-1954e6464174/go.mod h1:DqJ97dSdRW1W22yXSB90986pcOyQ7r45iio1KN2ez1A=
|
||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||
github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
|
||||
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
||||
github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=
|
||||
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
||||
github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/json-iterator/go v1.1.11 h1:uVUAXhF2To8cbw/3xN3pxj6kk7TYKs98NIrTqPlMWAQ=
|
||||
github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
||||
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
|
||||
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
|
||||
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
||||
github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
|
||||
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs=
|
||||
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8=
|
||||
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
|
||||
github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
|
||||
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI=
|
||||
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/pty v1.1.4 h1:5Myjjh3JY/NaAi4IsUbHADytDyl1VE1Y9PXDlL+P/VQ=
|
||||
github.com/kr/pty v1.1.4/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60=
|
||||
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
|
||||
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
||||
github.com/mattn/go-colorable v0.1.8 h1:c1ghPdyEDarC70ftn0y+A/Ee++9zz8ljHG1b13eJ0s8=
|
||||
github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
||||
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
||||
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
||||
github.com/mattn/go-isatty v0.0.13 h1:qdl+GuBjcsKKDco5BsxPJlId98mSWNKqYA+Co0SC1yA=
|
||||
github.com/mattn/go-isatty v0.0.13/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
||||
github.com/mattn/go-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4OSgU=
|
||||
github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b h1:j7+1HpAFS1zy5+Q4qx1fWh90gTKwiN4QCGoY9TWyyO4=
|
||||
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE=
|
||||
github.com/mholt/archiver v3.1.1+incompatible h1:1dCVxuqs0dJseYEhi5pl7MYPH9zDa1wBi7mF09cbNkU=
|
||||
github.com/mholt/archiver v3.1.1+incompatible/go.mod h1:Dh2dOXnSdiLxRiPoVfIr/fI1TwETms9B8CTWfeh7ROU=
|
||||
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
|
||||
github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
|
||||
github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||
github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
|
||||
github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg=
|
||||
github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY=
|
||||
github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||
github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI=
|
||||
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||
github.com/nwaples/rardecode v1.1.0 h1:vSxaY8vQhOcVr4mm5e8XllHWTiM4JF507A0Katqw7MQ=
|
||||
github.com/nwaples/rardecode v1.1.0/go.mod h1:5DzqNKiOdpKKBH87u8VlvAnPZMXcGRhxWkRpHbbfGS0=
|
||||
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
|
||||
github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
|
||||
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
|
||||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
|
||||
github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc=
|
||||
github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0=
|
||||
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
|
||||
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
|
||||
github.com/onsi/gomega v1.14.0 h1:ep6kpPVwmr/nTbklSx2nrLNSIO62DoYAhnPNIMhK8gI=
|
||||
github.com/onsi/gomega v1.14.0/go.mod h1:cIuvLEne0aoVhAgh/O6ac0Op8WWw9H6eYCriF+tEHG0=
|
||||
github.com/otiai10/copy v1.6.0 h1:IinKAryFFuPONZ7cm6T6E2QX/vcJwSnlaA5lfoaXIiQ=
|
||||
github.com/otiai10/copy v1.6.0/go.mod h1:XWfuS3CrI0R6IE0FbgHsEazaXO8G0LpMp9o8tos0x4E=
|
||||
github.com/otiai10/curr v0.0.0-20150429015615-9b4961190c95/go.mod h1:9qAhocn7zKJG+0mI8eUu6xqkFDYS2kb2saOteoSB3cE=
|
||||
github.com/otiai10/curr v1.0.0/go.mod h1:LskTG5wDwr8Rs+nNQ+1LlxRjAtTZZjtJW4rMXl6j4vs=
|
||||
github.com/otiai10/mint v1.3.0/go.mod h1:F5AjcsTsWUqX+Na9fpHb52P8pcRX2CI6A3ctIT91xUo=
|
||||
github.com/otiai10/mint v1.3.2 h1:VYWnrP5fXmz1MXvjuUvcBrXSjGE6xjON+axB/UrpO3E=
|
||||
github.com/otiai10/mint v1.3.2/go.mod h1:/yxELlJQ0ufhjUwhshSj+wFjZ78CnZ48/1wtmBH1OTc=
|
||||
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
|
||||
github.com/pelletier/go-toml v1.9.3/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
|
||||
github.com/pierrec/lz4 v2.6.1+incompatible h1:9UY3+iC23yxF0UfGaYrGplQ+79Rg+h/q9FV9ix19jjM=
|
||||
github.com/pierrec/lz4 v2.6.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
|
||||
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
|
||||
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
||||
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
|
||||
github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M=
|
||||
github.com/prometheus/client_golang v1.11.0 h1:HNkLOAEQMIDv/K+04rukrLx6ch7msSRwf3/SASFAGtQ=
|
||||
github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0=
|
||||
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M=
|
||||
github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
||||
github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo=
|
||||
github.com/prometheus/common v0.26.0 h1:iMAkS2TDoNWnKM+Kopnx/8tnEStIfpYA0ur0xQzzhMQ=
|
||||
github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc=
|
||||
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
||||
github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
|
||||
github.com/prometheus/procfs v0.6.0 h1:mxy4L2jP6qMonqmq+aTtOx1ifVWUgG/TAmntgbh3xv4=
|
||||
github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
|
||||
github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
|
||||
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
|
||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ=
|
||||
github.com/rs/zerolog v1.23.0 h1:UskrK+saS9P9Y789yNNulYKdARjPZuS35B8gJF2x60g=
|
||||
github.com/rs/zerolog v1.23.0/go.mod h1:6c7hFfxPOy7TacJc4Fcdi24/J0NKYGzjG8FWRI916Qo=
|
||||
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
|
||||
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
|
||||
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
|
||||
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
||||
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
|
||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
||||
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
|
||||
github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I=
|
||||
github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
||||
github.com/spf13/cobra v1.2.1 h1:+KmjbUw1hriSNMF55oPrkZcb27aECyrj8V2ytv7kWDw=
|
||||
github.com/spf13/cobra v1.2.1/go.mod h1:ExllRjgxM/piMAM+3tAZvg8fsklGAf3tPfi+i8t68Nk=
|
||||
github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo=
|
||||
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
||||
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
github.com/spf13/viper v1.8.1/go.mod h1:o0Pch8wJ9BVSWGQMbra6iw0oQ5oktSIBaujf1rJH9Ns=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.2.1/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
|
||||
github.com/ulikunitz/xz v0.5.6/go.mod h1:2bypXElzHzzJZwzH67Y6wb67pO62Rzfn7BSiF4ABRW8=
|
||||
github.com/ulikunitz/xz v0.5.10 h1:t92gobL9l3HE202wg3rlk19F6X+JOxl9BBrCCMYEYd8=
|
||||
github.com/ulikunitz/xz v0.5.10/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
|
||||
github.com/vbauerster/mpb/v7 v7.0.3 h1:NfX0pHWhlDTev15M/C3qmSTM1EiIjcS+/d6qS6H4FnI=
|
||||
github.com/vbauerster/mpb/v7 v7.0.3/go.mod h1:NXGsfPGx6G2JssqvEcULtDqUrxuuYs4llpv8W6ZUpzk=
|
||||
github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 h1:nIPpBwaJSVYIxUFsDv3M8ofmx9yWTog9BfvIu0q41lo=
|
||||
github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8/go.mod h1:HUYIGzjTL3rfEspMxjDjgmT5uz5wzYJKVo23qUhYTos=
|
||||
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
go.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs=
|
||||
go.etcd.io/etcd/client/pkg/v3 v3.5.0/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g=
|
||||
go.etcd.io/etcd/client/v2 v2.305.0/go.mod h1:h9puh54ZTgAKtEbut2oe9P4L/oqKCVB6xsXlzd7alYQ=
|
||||
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
|
||||
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
|
||||
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk=
|
||||
go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E=
|
||||
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
||||
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
|
||||
go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo=
|
||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190530122614-20be4c3c3ed5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||
golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=
|
||||
golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=
|
||||
golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
|
||||
golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
|
||||
golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
|
||||
golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
|
||||
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
|
||||
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
||||
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=
|
||||
golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
||||
golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
||||
golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
||||
golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
||||
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
|
||||
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
|
||||
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
|
||||
golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
|
||||
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||
golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo=
|
||||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
||||
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc=
|
||||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
||||
golang.org/x/net v0.0.0-20210428140749-89ef3d95e781 h1:DzZ89McO9/gWPsQXS/FVKAlG02ZjaQ6AlZRBimEYOd0=
|
||||
golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20210402161424-2e8d93401602/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c h1:F1jZWGFhYfh0Ci55sIpILtKKK8p3i2/krTr0H1rg74I=
|
||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210503060354-a79de5458b56/go.mod h1:tfny5GFUkzUvx4ps4ajbZsCe5lw1metzhBm9T3x7oIY=
|
||||
golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b h1:9zKuko04nR4gjZ4+DNjHqRlAJqbJETHwiNKDqTfOjfE=
|
||||
golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
|
||||
golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
|
||||
golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=
|
||||
golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||
golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||
golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||
golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE=
|
||||
golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
|
||||
golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
|
||||
google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
|
||||
google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
|
||||
google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
|
||||
google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
|
||||
google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
|
||||
google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
|
||||
google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
||||
google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
||||
google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
||||
google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
||||
google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
||||
google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
|
||||
google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
|
||||
google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM=
|
||||
google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc=
|
||||
google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg=
|
||||
google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE=
|
||||
google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8=
|
||||
google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU=
|
||||
google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94=
|
||||
google.golang.org/api v0.44.0/go.mod h1:EBOGZqzyhtvMDoxwS97ctnh0zUmYY6CxqXsc1AvkYD8=
|
||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
|
||||
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||
google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||
google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||
google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
|
||||
google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA=
|
||||
google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U=
|
||||
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
|
||||
google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA=
|
||||
google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A=
|
||||
google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
|
||||
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
||||
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
|
||||
google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||
google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||
google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60=
|
||||
google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
|
||||
google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
||||
google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
||||
google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
||||
google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=
|
||||
google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
|
||||
google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8=
|
||||
google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
|
||||
google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
|
||||
google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
|
||||
google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
|
||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
||||
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
|
||||
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
|
||||
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
|
||||
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
|
||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||
google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk=
|
||||
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
||||
gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
||||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
|
||||
honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
|
||||
honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
|
||||
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
|
||||
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
|
||||
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
|
||||
285
pkg/bootstraps/build.go
Normal file
285
pkg/bootstraps/build.go
Normal file
|
|
@ -0,0 +1,285 @@
|
|||
// Copyright 2021 storyicon@foxmail.com
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package bootstraps
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/storyicon/powerproto/pkg/component/actionmanager"
|
||||
"github.com/storyicon/powerproto/pkg/component/compilermanager"
|
||||
"github.com/storyicon/powerproto/pkg/component/configmanager"
|
||||
"github.com/storyicon/powerproto/pkg/component/pluginmanager"
|
||||
"github.com/storyicon/powerproto/pkg/configs"
|
||||
"github.com/storyicon/powerproto/pkg/util"
|
||||
"github.com/storyicon/powerproto/pkg/util/command"
|
||||
"github.com/storyicon/powerproto/pkg/util/concurrent"
|
||||
"github.com/storyicon/powerproto/pkg/util/logger"
|
||||
"github.com/storyicon/powerproto/pkg/util/progressbar"
|
||||
)
|
||||
|
||||
// StepLookUpConfigs is used to lookup config files according to target proto files
|
||||
func StepLookUpConfigs(
|
||||
ctx context.Context,
|
||||
targets []string,
|
||||
configManager configmanager.ConfigManager,
|
||||
) ([]configs.ConfigItem, error) {
|
||||
progress := progressbar.GetProgressBar(len(targets))
|
||||
progress.SetPrefix("Lookup configs of proto files")
|
||||
var configItems []configs.ConfigItem
|
||||
deduplicate := map[string]struct{}{}
|
||||
for _, target := range targets {
|
||||
cfg, err := configManager.GetConfig(ctx, target)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if _, exists := deduplicate[cfg.ID()]; !exists {
|
||||
configItems = append(configItems, cfg)
|
||||
deduplicate[cfg.ID()] = struct{}{}
|
||||
}
|
||||
progress.SetSuffix("load %s", cfg.ID())
|
||||
progress.Incr()
|
||||
}
|
||||
progress.SetSuffix("success!")
|
||||
progress.Wait()
|
||||
fmt.Printf("the following %d configurations will be used: \r\n", len(configItems))
|
||||
for _, config := range configItems {
|
||||
fmt.Printf(" %s \r\n", config.Path())
|
||||
}
|
||||
if len(configItems) == 0 {
|
||||
return nil, errors.New("no config file matched, please check the scope of config file " +
|
||||
"or use 'powerproto init' to create config file")
|
||||
}
|
||||
return configItems, nil
|
||||
}
|
||||
|
||||
// StepInstallProtoc is used to install protoc
|
||||
func StepInstallProtoc(ctx context.Context,
|
||||
pluginManager pluginmanager.PluginManager,
|
||||
configItems []configs.ConfigItem) error {
|
||||
deduplicate := map[string]struct{}{}
|
||||
for _, config := range configItems {
|
||||
version := config.Config().Protoc
|
||||
deduplicate[version] = struct{}{}
|
||||
}
|
||||
progress := progressbar.GetProgressBar(len(deduplicate))
|
||||
progress.SetPrefix("Install protoc")
|
||||
|
||||
versionsMap := map[string]struct{}{}
|
||||
for version := range deduplicate {
|
||||
if version == "latest" {
|
||||
progress.SetSuffix("query latest version of protoc")
|
||||
latestVersion, err := pluginManager.GetProtocLatestVersion(ctx)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to list protoc versions")
|
||||
}
|
||||
version = latestVersion
|
||||
}
|
||||
progress.SetSuffix("check cache of protoc %s", version)
|
||||
exists, _, err := pluginManager.IsProtocInstalled(ctx, version)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if exists {
|
||||
progress.SetSuffix("the %s version of protoc is already cached", version)
|
||||
} else {
|
||||
progress.SetSuffix("install %s version of protoc", version)
|
||||
_, err = pluginManager.InstallProtoc(ctx, version)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
progress.SetSuffix("the %s version of protoc is installed", version)
|
||||
}
|
||||
versionsMap[version] = struct{}{}
|
||||
progress.Incr()
|
||||
}
|
||||
progress.Wait()
|
||||
fmt.Println("the following versions of protoc will be used:", util.SetToSlice(versionsMap))
|
||||
return nil
|
||||
}
|
||||
|
||||
// StepInstallPlugins is used to install plugins
|
||||
func StepInstallPlugins(ctx context.Context,
|
||||
pluginManager pluginmanager.PluginManager,
|
||||
configItems []configs.ConfigItem,
|
||||
) error {
|
||||
deduplicate := map[string]struct{}{}
|
||||
for _, config := range configItems {
|
||||
for _, pkg := range config.Config().Plugins {
|
||||
deduplicate[pkg] = struct{}{}
|
||||
}
|
||||
}
|
||||
progress := progressbar.GetProgressBar(len(deduplicate))
|
||||
progress.SetPrefix("Install plugins")
|
||||
pluginsMap := map[string]struct{}{}
|
||||
for pkg := range deduplicate {
|
||||
path, version, ok := util.SplitGoPackageVersion(pkg)
|
||||
if !ok {
|
||||
return errors.Errorf("invalid format: %s, should in path@version format", pkg)
|
||||
}
|
||||
if version == "latest" {
|
||||
progress.SetSuffix("query latest version of %s", path)
|
||||
data, err := pluginManager.GetPluginLatestVersion(ctx, path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
version = data
|
||||
pkg = util.JoinGoPackageVersion(path, version)
|
||||
}
|
||||
progress.SetSuffix("check cache of %s", pkg)
|
||||
exists, _, err := pluginManager.IsPluginInstalled(ctx, path, version)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if exists {
|
||||
progress.SetSuffix("%s is cached", pkg)
|
||||
} else {
|
||||
progress.SetSuffix("installing %s", pkg)
|
||||
_, err := pluginManager.InstallPlugin(ctx, path, version)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
progress.SetSuffix("%s installed", pkg)
|
||||
}
|
||||
pluginsMap[pkg] = struct{}{}
|
||||
progress.Incr()
|
||||
}
|
||||
progress.SetSuffix("all plugins have been installed")
|
||||
progress.Wait()
|
||||
|
||||
fmt.Println("the following plugins will be used:")
|
||||
for pkg := range pluginsMap {
|
||||
fmt.Printf(" %s\r\n", pkg)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// StepCompile is used to compile proto files
|
||||
func StepCompile(ctx context.Context,
|
||||
compilerManager compilermanager.CompilerManager,
|
||||
targets []string,
|
||||
) error {
|
||||
progress := progressbar.GetProgressBar(len(targets))
|
||||
progress.SetPrefix("Compile Proto Files")
|
||||
c := concurrent.NewErrGroup(ctx, 10)
|
||||
for _, target := range targets {
|
||||
func(target string) {
|
||||
c.Go(func(ctx context.Context) error {
|
||||
progress.SetSuffix(target)
|
||||
comp, err := compilerManager.GetCompiler(ctx, target)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := comp.Compile(ctx, target); err != nil {
|
||||
return err
|
||||
}
|
||||
progress.Incr()
|
||||
return nil
|
||||
})
|
||||
}(target)
|
||||
}
|
||||
if err := c.Wait(); err != nil {
|
||||
return err
|
||||
}
|
||||
progress.Wait()
|
||||
return nil
|
||||
}
|
||||
|
||||
// StepPostAction is used to execute post actions
|
||||
func StepPostAction(ctx context.Context,
|
||||
actionsManager actionmanager.ActionManager,
|
||||
configItems []configs.ConfigItem) error {
|
||||
progress := progressbar.GetProgressBar(len(configItems))
|
||||
progress.SetPrefix("PostAction")
|
||||
for _, cfg := range configItems {
|
||||
progress.SetSuffix(cfg.Path())
|
||||
if err := actionsManager.ExecutePostAction(ctx, cfg); err != nil {
|
||||
return err
|
||||
}
|
||||
progress.Incr()
|
||||
}
|
||||
progress.Wait()
|
||||
return nil
|
||||
}
|
||||
|
||||
// StepPostShell is used to execute post shell
|
||||
func StepPostShell(ctx context.Context,
|
||||
actionsManager actionmanager.ActionManager,
|
||||
configItems []configs.ConfigItem) error {
|
||||
progress := progressbar.GetProgressBar(len(configItems))
|
||||
progress.SetPrefix("PostShell")
|
||||
for _, cfg := range configItems {
|
||||
progress.SetSuffix(cfg.Path())
|
||||
if err := actionsManager.ExecutePostShell(ctx, cfg); err != nil {
|
||||
return err
|
||||
}
|
||||
progress.Incr()
|
||||
}
|
||||
progress.Wait()
|
||||
return nil
|
||||
}
|
||||
|
||||
// Compile is used to compile proto files
|
||||
func Compile(ctx context.Context, targets []string) error {
|
||||
log := logger.NewDefault("compile")
|
||||
log.SetLogLevel(logger.LevelError)
|
||||
|
||||
configManager, err := configmanager.NewConfigManager(log)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
pluginManager, err := pluginmanager.NewPluginManager(pluginmanager.NewConfig(), log)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
compilerManager, err := compilermanager.NewCompilerManager(ctx, log, configManager, pluginManager)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
actionManager, err := actionmanager.NewActionManager(log)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
configItems, err := StepLookUpConfigs(ctx, targets, configManager)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := StepInstallProtoc(ctx, pluginManager, configItems); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := StepInstallPlugins(ctx, pluginManager, configItems); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := StepCompile(ctx, compilerManager, targets); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !command.IsDisableAction(ctx) {
|
||||
if err := StepPostAction(ctx, actionManager, configItems); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := StepPostShell(ctx, actionManager, configItems); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
log.LogWarn(nil, "PostAction and PostShell is skipped. If you need to allow execution, please append '-a' to command flags to enable")
|
||||
}
|
||||
|
||||
log.LogInfo(nil, "Good job! you are ready to go :)")
|
||||
return nil
|
||||
}
|
||||
118
pkg/bootstraps/tidy.go
Normal file
118
pkg/bootstraps/tidy.go
Normal file
|
|
@ -0,0 +1,118 @@
|
|||
// Copyright 2021 storyicon@foxmail.com
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package bootstraps
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/storyicon/powerproto/pkg/component/configmanager"
|
||||
"github.com/storyicon/powerproto/pkg/component/pluginmanager"
|
||||
"github.com/storyicon/powerproto/pkg/configs"
|
||||
"github.com/storyicon/powerproto/pkg/util"
|
||||
"github.com/storyicon/powerproto/pkg/util/logger"
|
||||
"github.com/storyicon/powerproto/pkg/util/progressbar"
|
||||
)
|
||||
|
||||
// StepTidyConfig is used to tidy configs by proto file targets
|
||||
func StepTidyConfig(ctx context.Context, targets []string) error {
|
||||
log := logger.NewDefault("tidy")
|
||||
log.SetLogLevel(logger.LevelError)
|
||||
|
||||
configManager, err := configmanager.NewConfigManager(log)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
pluginManager, err := pluginmanager.NewPluginManager(pluginmanager.NewConfig(), log)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
configPaths := map[string]struct{}{}
|
||||
for _, target := range targets {
|
||||
cfg, err := configManager.GetConfig(ctx, target)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
configPaths[cfg.Path()] = struct{}{}
|
||||
}
|
||||
if len(configPaths) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
progress := progressbar.GetProgressBar(len(configPaths))
|
||||
progress.SetPrefix("tidy configs")
|
||||
for path := range configPaths {
|
||||
progress.SetSuffix(path)
|
||||
err := StepTidyConfigFile(ctx, pluginManager, progress, path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
progress.Incr()
|
||||
}
|
||||
progress.SetSuffix("success!")
|
||||
progress.Wait()
|
||||
return nil
|
||||
}
|
||||
|
||||
// StepTidyConfig is used clean config
|
||||
// It will amend the 'latest' version to the latest version number in 'vx.y.z' format
|
||||
func StepTidyConfigFile(ctx context.Context,
|
||||
pluginManager pluginmanager.PluginManager,
|
||||
progress progressbar.ProgressBar,
|
||||
configFilePath string,
|
||||
) error {
|
||||
progress.SetSuffix("load config: %s", configFilePath)
|
||||
configItems, err := configs.LoadConfigs(configFilePath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var cleanable bool
|
||||
for _, item := range configItems {
|
||||
if item.Protoc == "latest" {
|
||||
progress.SetSuffix("query latest version of protoc")
|
||||
version, err := pluginManager.GetProtocLatestVersion(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
item.Protoc = version
|
||||
cleanable = true
|
||||
}
|
||||
for name, pkg := range item.Plugins {
|
||||
path, version, ok := util.SplitGoPackageVersion(pkg)
|
||||
if !ok {
|
||||
return errors.Errorf("invalid package format: %s, should be in path@version format", pkg)
|
||||
}
|
||||
if version == "latest" {
|
||||
progress.SetSuffix("query latest version of %s", path)
|
||||
version, err := pluginManager.GetPluginLatestVersion(ctx, path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
item.Plugins[name] = util.JoinGoPackageVersion(path, version)
|
||||
cleanable = true
|
||||
}
|
||||
}
|
||||
}
|
||||
if cleanable {
|
||||
progress.SetSuffix("save %s", configFilePath)
|
||||
if err := configs.SaveConfigs(configFilePath, configItems...); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
progress.SetSuffix("config file tidied: %s", configFilePath)
|
||||
return nil
|
||||
}
|
||||
31
pkg/component/actionmanager/actions/actions.go
Normal file
31
pkg/component/actionmanager/actions/actions.go
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
// Copyright 2021 storyicon@foxmail.com
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package actions
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/storyicon/powerproto/pkg/util/logger"
|
||||
)
|
||||
|
||||
// CommonOptions is common options of action
|
||||
type CommonOptions struct {
|
||||
ConfigFilePath string
|
||||
}
|
||||
|
||||
// ActionFunc defines the common prototype of action func
|
||||
type ActionFunc func(ctx context.Context,
|
||||
log logger.Logger,
|
||||
args []string, options *CommonOptions) error
|
||||
64
pkg/component/actionmanager/actions/copy.go
Normal file
64
pkg/component/actionmanager/actions/copy.go
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
// Copyright 2021 storyicon@foxmail.com
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package actions
|
||||
|
||||
import (
|
||||
"context"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/storyicon/powerproto/pkg/util"
|
||||
"github.com/storyicon/powerproto/pkg/util/command"
|
||||
"github.com/storyicon/powerproto/pkg/util/logger"
|
||||
)
|
||||
|
||||
// ActionCopy is used to copy directory or file from src to dest
|
||||
// Its args prototype is:
|
||||
// args: (src string, dest string)
|
||||
func ActionCopy(ctx context.Context, log logger.Logger, args []string, options *CommonOptions) error {
|
||||
if len(args) != 2 || util.ContainsEmpty(args...) {
|
||||
return errors.Errorf("expected length of args is 3, but received %d", len(args))
|
||||
}
|
||||
var (
|
||||
source = args[0]
|
||||
destination = args[1]
|
||||
path = filepath.Dir(options.ConfigFilePath)
|
||||
absSource = filepath.Join(path, source)
|
||||
absDestination = filepath.Join(path, destination)
|
||||
)
|
||||
|
||||
if filepath.IsAbs(source) {
|
||||
return errors.Errorf("absolute source %s is not allowed in action move", source)
|
||||
}
|
||||
|
||||
if filepath.IsAbs(destination) {
|
||||
return errors.Errorf("absolute destination %s is not allowed in action move", destination)
|
||||
}
|
||||
|
||||
if command.IsDryRun(ctx) {
|
||||
log.LogInfo(map[string]interface{}{
|
||||
"action": "copy",
|
||||
"from": absSource,
|
||||
"to": absDestination,
|
||||
}, "DryRun")
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := util.CopyDirectory(absSource, absDestination); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
68
pkg/component/actionmanager/actions/move.go
Normal file
68
pkg/component/actionmanager/actions/move.go
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
// Copyright 2021 storyicon@foxmail.com
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package actions
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/storyicon/powerproto/pkg/util"
|
||||
"github.com/storyicon/powerproto/pkg/util/command"
|
||||
"github.com/storyicon/powerproto/pkg/util/logger"
|
||||
)
|
||||
|
||||
// ActionMove is used to move directory or file from src to dest
|
||||
// Its args prototype is:
|
||||
// args: (src string, dest string)
|
||||
func ActionMove(ctx context.Context, log logger.Logger, args []string, options *CommonOptions) error {
|
||||
if len(args) != 2 || util.ContainsEmpty(args...) {
|
||||
return errors.Errorf("expected length of args is 3, but received %d", len(args))
|
||||
}
|
||||
var (
|
||||
source = args[0]
|
||||
destination = args[1]
|
||||
path = filepath.Dir(options.ConfigFilePath)
|
||||
absSource = filepath.Join(path, source)
|
||||
absDestination = filepath.Join(path, destination)
|
||||
)
|
||||
|
||||
if filepath.IsAbs(source) {
|
||||
return errors.Errorf("absolute source %s is not allowed in action move", source)
|
||||
}
|
||||
|
||||
if filepath.IsAbs(destination) {
|
||||
return errors.Errorf("absolute destination %s is not allowed in action move", destination)
|
||||
}
|
||||
|
||||
if command.IsDryRun(ctx) {
|
||||
log.LogInfo(map[string]interface{}{
|
||||
"action": "move",
|
||||
"from": absSource,
|
||||
"to": absDestination,
|
||||
}, "DryRun")
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := util.CopyDirectory(absSource, absDestination); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := os.RemoveAll(absSource); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
51
pkg/component/actionmanager/actions/remove.go
Normal file
51
pkg/component/actionmanager/actions/remove.go
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
// Copyright 2021 storyicon@foxmail.com
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package actions
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/storyicon/powerproto/pkg/util/command"
|
||||
"github.com/storyicon/powerproto/pkg/util/logger"
|
||||
)
|
||||
|
||||
// ActionRemove is used to delete directories or files
|
||||
// Its args prototype is:
|
||||
// args: (path ...string)
|
||||
func ActionRemove(ctx context.Context, log logger.Logger, args []string, options *CommonOptions) error {
|
||||
for _, arg := range args {
|
||||
if filepath.IsAbs(arg) {
|
||||
return errors.Errorf("absolute path %s is not allowed in action remove", arg)
|
||||
}
|
||||
path := filepath.Join(filepath.Dir(options.ConfigFilePath), arg)
|
||||
|
||||
if command.IsDryRun(ctx) {
|
||||
log.LogInfo(map[string]interface{}{
|
||||
"action": "remove",
|
||||
"target": path,
|
||||
}, "DryRun")
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := os.RemoveAll(path); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
80
pkg/component/actionmanager/actions/replace.go
Normal file
80
pkg/component/actionmanager/actions/replace.go
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
// Copyright 2021 storyicon@foxmail.com
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package actions
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"io/fs"
|
||||
"io/ioutil"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/storyicon/powerproto/pkg/util"
|
||||
"github.com/storyicon/powerproto/pkg/util/command"
|
||||
"github.com/storyicon/powerproto/pkg/util/logger"
|
||||
)
|
||||
|
||||
// ActionReplace is used to replace text in bulk
|
||||
// Its args prototype is:
|
||||
// args: (pattern string, from string, to string)
|
||||
// pattern is used to match files
|
||||
func ActionReplace(ctx context.Context, log logger.Logger, args []string, options *CommonOptions) error {
|
||||
if len(args) != 3 {
|
||||
return errors.Errorf("expected length of args is 3, but received %d", len(args))
|
||||
}
|
||||
var (
|
||||
pattern = args[0]
|
||||
path = filepath.Dir(options.ConfigFilePath)
|
||||
from = args[1]
|
||||
to = args[2]
|
||||
)
|
||||
|
||||
if pattern == "" || from == "" {
|
||||
return errors.Errorf("pattern and from arguments in action replace can not be empty")
|
||||
}
|
||||
if filepath.IsAbs(pattern) {
|
||||
return errors.Errorf("absolute path %s is not allowed in action replace", pattern)
|
||||
}
|
||||
pattern = filepath.Join(path, pattern)
|
||||
return filepath.Walk(path, func(path string, info fs.FileInfo, err error) error {
|
||||
if info.IsDir() {
|
||||
return nil
|
||||
}
|
||||
matched, err := util.MatchPath(pattern, path)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if matched {
|
||||
if command.IsDryRun(ctx) {
|
||||
log.LogInfo(map[string]interface{}{
|
||||
"action": "replace",
|
||||
"file": path,
|
||||
"from": from,
|
||||
"to": to,
|
||||
}, "DryRun")
|
||||
return nil
|
||||
}
|
||||
data, err := ioutil.ReadFile(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
data = bytes.ReplaceAll(data, []byte(from), []byte(to))
|
||||
return ioutil.WriteFile(path, data, fs.ModePerm)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
42
pkg/component/actionmanager/errors.go
Normal file
42
pkg/component/actionmanager/errors.go
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
// Copyright 2021 storyicon@foxmail.com
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package actionmanager
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/storyicon/powerproto/pkg/util/command"
|
||||
)
|
||||
|
||||
// ErrPostShell defines the post shell command error
|
||||
type ErrPostShell struct {
|
||||
Path string
|
||||
*command.ErrCommandExec
|
||||
}
|
||||
|
||||
// ErrPostAction defines the post action error
|
||||
type ErrPostAction struct {
|
||||
Path string
|
||||
Name string
|
||||
Arguments []string
|
||||
Err error
|
||||
}
|
||||
|
||||
// Error implements the standard error interface
|
||||
func (err *ErrPostAction) Error() string {
|
||||
return fmt.Sprintf("failed to execute action: %s, path: %s, arguments: %s, err: %s",
|
||||
err.Name, err.Path, err.Arguments, err.Err,
|
||||
)
|
||||
}
|
||||
100
pkg/component/actionmanager/manager.go
Normal file
100
pkg/component/actionmanager/manager.go
Normal file
|
|
@ -0,0 +1,100 @@
|
|||
// Copyright 2021 storyicon@foxmail.com
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package actionmanager
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/storyicon/powerproto/pkg/component/actionmanager/actions"
|
||||
"github.com/storyicon/powerproto/pkg/configs"
|
||||
"github.com/storyicon/powerproto/pkg/util/command"
|
||||
"github.com/storyicon/powerproto/pkg/util/logger"
|
||||
)
|
||||
|
||||
// ActionManager is used to manage actions
|
||||
type ActionManager interface {
|
||||
// ExecutePostShell is used to execute post shell in config item
|
||||
ExecutePostShell(ctx context.Context, config configs.ConfigItem) error
|
||||
// ExecutePostAction is used to execute post action in config item
|
||||
ExecutePostAction(ctx context.Context, config configs.ConfigItem) error
|
||||
}
|
||||
|
||||
// BasicActionManager is a basic implement of ActionManager
|
||||
type BasicActionManager struct {
|
||||
logger.Logger
|
||||
|
||||
// map[string]ActionFunc
|
||||
actions map[string]actions.ActionFunc
|
||||
}
|
||||
|
||||
// NewActionManager is used to create action manager
|
||||
func NewActionManager(log logger.Logger) (ActionManager, error) {
|
||||
return NewBasicActionManager(log)
|
||||
}
|
||||
|
||||
// NewBasicActionManager is used to create a BasicActionManager
|
||||
func NewBasicActionManager(log logger.Logger) (*BasicActionManager, error) {
|
||||
return &BasicActionManager{
|
||||
Logger: log.NewLogger("actionmanager"),
|
||||
actions: map[string]actions.ActionFunc{
|
||||
"move": actions.ActionMove,
|
||||
"replace": actions.ActionReplace,
|
||||
"remove": actions.ActionRemove,
|
||||
"copy": actions.ActionCopy,
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
// ExecutePostShell is used to execute post shell in config item
|
||||
func (m *BasicActionManager) ExecutePostShell(ctx context.Context, config configs.ConfigItem) error {
|
||||
script := config.Config().PostShell
|
||||
if script == "" {
|
||||
return nil
|
||||
}
|
||||
dir := filepath.Dir(config.Path())
|
||||
_, err := command.Execute(ctx, m.Logger, dir, "/bin/sh", []string{
|
||||
"-c", script,
|
||||
}, nil)
|
||||
if err != nil {
|
||||
return &ErrPostShell{
|
||||
Path: config.Path(),
|
||||
ErrCommandExec: err,
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ExecutePostAction is used to execute post action in config item
|
||||
func (m *BasicActionManager) ExecutePostAction(ctx context.Context, config configs.ConfigItem) error {
|
||||
for _, action := range config.Config().PostActions {
|
||||
actionFunc, ok := m.actions[action.Name]
|
||||
if !ok {
|
||||
return fmt.Errorf("unknown action: %s", action.Name)
|
||||
}
|
||||
if err := actionFunc(ctx, m.Logger, action.Args, &actions.CommonOptions{
|
||||
ConfigFilePath: config.Path(),
|
||||
}); err != nil {
|
||||
return &ErrPostAction{
|
||||
Path: config.Path(),
|
||||
Name: action.Name,
|
||||
Arguments: action.Args,
|
||||
Err: err,
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
179
pkg/component/compilermanager/compiler.go
Normal file
179
pkg/component/compilermanager/compiler.go
Normal file
|
|
@ -0,0 +1,179 @@
|
|||
// Copyright 2021 storyicon@foxmail.com
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package compilermanager
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/storyicon/powerproto/pkg/component/pluginmanager"
|
||||
"github.com/storyicon/powerproto/pkg/configs"
|
||||
"github.com/storyicon/powerproto/pkg/consts"
|
||||
"github.com/storyicon/powerproto/pkg/util"
|
||||
"github.com/storyicon/powerproto/pkg/util/command"
|
||||
"github.com/storyicon/powerproto/pkg/util/logger"
|
||||
)
|
||||
|
||||
// Compiler is used to compile proto file
|
||||
type Compiler interface {
|
||||
// Compile is used to compile proto file
|
||||
Compile(ctx context.Context, protoFilePath string) error
|
||||
// GetConfig is used to return config that the compiler used
|
||||
GetConfig(ctx context.Context) configs.ConfigItem
|
||||
}
|
||||
|
||||
var _ Compiler = &BasicCompiler{}
|
||||
|
||||
// BasicCompiler is the basic implement of Compiler
|
||||
type BasicCompiler struct {
|
||||
logger.Logger
|
||||
config configs.ConfigItem
|
||||
pluginManager pluginmanager.PluginManager
|
||||
|
||||
protocPath string
|
||||
arguments []string
|
||||
dir string
|
||||
}
|
||||
|
||||
// NewCompiler is used to create a compiler
|
||||
func NewCompiler(
|
||||
ctx context.Context,
|
||||
log logger.Logger,
|
||||
pluginManager pluginmanager.PluginManager,
|
||||
config configs.ConfigItem,
|
||||
) (Compiler, error) {
|
||||
return NewBasicCompiler(ctx, log, pluginManager, config)
|
||||
}
|
||||
|
||||
// NewBasicCompiler is used to create a basic compiler
|
||||
func NewBasicCompiler(
|
||||
ctx context.Context,
|
||||
log logger.Logger,
|
||||
pluginManager pluginmanager.PluginManager,
|
||||
config configs.ConfigItem,
|
||||
) (*BasicCompiler, error) {
|
||||
basic := &BasicCompiler{
|
||||
Logger: log.NewLogger("compiler"),
|
||||
config: config,
|
||||
pluginManager: pluginManager,
|
||||
}
|
||||
if err := basic.calcProto(ctx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := basic.calcArguments(ctx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := basic.calcDir(ctx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return basic, nil
|
||||
}
|
||||
|
||||
|
||||
// Compile is used to compile proto file
|
||||
func (b *BasicCompiler) Compile(ctx context.Context, protoFilePath string) error {
|
||||
arguments := make([]string, len(b.arguments))
|
||||
copy(arguments, b.arguments)
|
||||
arguments = append(arguments, protoFilePath)
|
||||
_, err := command.Execute(ctx,
|
||||
b.Logger, b.dir, b.protocPath, arguments, nil)
|
||||
if err != nil {
|
||||
return &ErrCompile{
|
||||
ErrCommandExec: err,
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetConfig is used to return config that the compiler used
|
||||
func (b *BasicCompiler) GetConfig(ctx context.Context) configs.ConfigItem {
|
||||
return b.config
|
||||
}
|
||||
|
||||
func (b *BasicCompiler) calcDir(ctx context.Context) error {
|
||||
if dir := b.config.Config().ProtocWorkDir; dir != "" {
|
||||
dir = util.RenderPathWithEnv(dir)
|
||||
if !filepath.IsAbs(dir) {
|
||||
dir = filepath.Join(b.config.Path(), dir)
|
||||
}
|
||||
b.dir = dir
|
||||
} else {
|
||||
b.dir = filepath.Dir(b.config.Path())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *BasicCompiler) calcProto(ctx context.Context) error {
|
||||
cfg := b.config
|
||||
protocVersion := cfg.Config().Protoc
|
||||
if protocVersion == "latest" {
|
||||
latestVersion, err := b.pluginManager.GetProtocLatestVersion(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
protocVersion = latestVersion
|
||||
}
|
||||
localPath, err := b.pluginManager.InstallProtoc(ctx, protocVersion)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
b.protocPath = localPath
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *BasicCompiler) calcArguments(ctx context.Context) error {
|
||||
cfg := b.config
|
||||
arguments := make([]string, len(cfg.Config().Options))
|
||||
copy(arguments, cfg.Config().Options)
|
||||
|
||||
dir := filepath.Dir(cfg.Path())
|
||||
// build import paths
|
||||
for _, path := range cfg.Config().ImportPaths {
|
||||
if path == consts.KeyPowerProtoInclude {
|
||||
path = b.pluginManager.IncludePath(ctx)
|
||||
}
|
||||
path = util.RenderPathWithEnv(path)
|
||||
if !filepath.IsAbs(path) {
|
||||
path = filepath.Join(dir, path)
|
||||
}
|
||||
arguments = append(arguments, "--proto_path="+path)
|
||||
}
|
||||
|
||||
// build plugin options
|
||||
for name, pkg := range cfg.Config().Plugins {
|
||||
path, version, ok := util.SplitGoPackageVersion(pkg)
|
||||
if !ok {
|
||||
return errors.Errorf("failed to parse: %s", pkg)
|
||||
}
|
||||
if version == "latest" {
|
||||
latestVersion, err := b.pluginManager.GetPluginLatestVersion(ctx, path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
version = latestVersion
|
||||
}
|
||||
local, err := b.pluginManager.InstallPlugin(ctx, path, version)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to get plugin path")
|
||||
}
|
||||
arg := fmt.Sprintf("--plugin=%s=%s", name, local)
|
||||
arguments = append(arguments, arg)
|
||||
}
|
||||
b.arguments = arguments
|
||||
return nil
|
||||
}
|
||||
24
pkg/component/compilermanager/errors.go
Normal file
24
pkg/component/compilermanager/errors.go
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
// Copyright 2021 storyicon@foxmail.com
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package compilermanager
|
||||
|
||||
import (
|
||||
"github.com/storyicon/powerproto/pkg/util/command"
|
||||
)
|
||||
|
||||
// ErrCompile defines the compile error
|
||||
type ErrCompile struct {
|
||||
*command.ErrCommandExec
|
||||
}
|
||||
88
pkg/component/compilermanager/manager.go
Normal file
88
pkg/component/compilermanager/manager.go
Normal file
|
|
@ -0,0 +1,88 @@
|
|||
// Copyright 2021 storyicon@foxmail.com
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package compilermanager
|
||||
|
||||
import (
|
||||
"context"
|
||||
"sync"
|
||||
|
||||
"github.com/storyicon/powerproto/pkg/component/configmanager"
|
||||
"github.com/storyicon/powerproto/pkg/component/pluginmanager"
|
||||
"github.com/storyicon/powerproto/pkg/util/logger"
|
||||
)
|
||||
|
||||
// CompilerManager is to manage compiler
|
||||
type CompilerManager interface {
|
||||
// GetCompiler is used to get compiler of specified proto file path
|
||||
GetCompiler(ctx context.Context, protoFilePath string) (Compiler, error)
|
||||
}
|
||||
|
||||
// BasicCompilerManager is the basic implement of CompilerManager
|
||||
type BasicCompilerManager struct {
|
||||
logger.Logger
|
||||
|
||||
configManager configmanager.ConfigManager
|
||||
pluginManager pluginmanager.PluginManager
|
||||
|
||||
tree map[string]Compiler
|
||||
treeLock sync.RWMutex
|
||||
}
|
||||
|
||||
var _ CompilerManager = &BasicCompilerManager{}
|
||||
|
||||
// NewCompilerManager is used to create CompilerManager
|
||||
func NewCompilerManager(ctx context.Context,
|
||||
log logger.Logger,
|
||||
configManager configmanager.ConfigManager,
|
||||
pluginManager pluginmanager.PluginManager,
|
||||
) (CompilerManager, error) {
|
||||
return NewBasicCompilerManager(ctx, log, configManager, pluginManager)
|
||||
}
|
||||
|
||||
// BasicCompilerManager is used to create basic CompilerManager
|
||||
func NewBasicCompilerManager(ctx context.Context,
|
||||
log logger.Logger,
|
||||
configManager configmanager.ConfigManager,
|
||||
pluginManager pluginmanager.PluginManager,
|
||||
) (*BasicCompilerManager, error) {
|
||||
return &BasicCompilerManager{
|
||||
Logger: log.NewLogger("compilermanager"),
|
||||
configManager: configManager,
|
||||
pluginManager: pluginManager,
|
||||
tree: map[string]Compiler{},
|
||||
}, nil
|
||||
}
|
||||
|
||||
// GetCompiler is used to get compiler of specified proto file path
|
||||
func (b *BasicCompilerManager) GetCompiler(ctx context.Context, protoFilePath string) (Compiler, error) {
|
||||
config, err := b.configManager.GetConfig(ctx, protoFilePath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
b.treeLock.Lock()
|
||||
defer b.treeLock.Unlock()
|
||||
c, ok := b.tree[config.Path()]
|
||||
if ok {
|
||||
return c, nil
|
||||
}
|
||||
|
||||
compiler, err := NewCompiler(ctx, b.Logger, b.pluginManager, config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b.tree[config.ID()] = compiler
|
||||
return compiler, nil
|
||||
}
|
||||
103
pkg/component/configmanager/manager.go
Normal file
103
pkg/component/configmanager/manager.go
Normal file
|
|
@ -0,0 +1,103 @@
|
|||
// Copyright 2021 storyicon@foxmail.com
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package configmanager
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/storyicon/powerproto/pkg/configs"
|
||||
"github.com/storyicon/powerproto/pkg/util/logger"
|
||||
)
|
||||
|
||||
// ConfigManager is used to manage config
|
||||
type ConfigManager interface {
|
||||
// GetCompiler is used to get config of specified proto file path
|
||||
GetConfig(ctx context.Context, protoFilePath string) (configs.ConfigItem, error)
|
||||
}
|
||||
|
||||
// NewConfigManager is used to create ConfigManager
|
||||
func NewConfigManager(log logger.Logger) (ConfigManager, error) {
|
||||
return NewBasicConfigManager(log)
|
||||
}
|
||||
|
||||
// BasicConfigManager is the basic implement of ConfigManager
|
||||
type BasicConfigManager struct {
|
||||
logger.Logger
|
||||
|
||||
tree map[string][]configs.ConfigItem
|
||||
treeLock sync.RWMutex
|
||||
}
|
||||
|
||||
// New is used to create a basic ConfigManager
|
||||
func NewBasicConfigManager(log logger.Logger) (*BasicConfigManager, error) {
|
||||
return &BasicConfigManager{
|
||||
Logger: log.NewLogger("configmanager"),
|
||||
tree: map[string][]configs.ConfigItem{},
|
||||
}, nil
|
||||
}
|
||||
|
||||
// GetCompiler is used to get config of specified proto file path
|
||||
func (b *BasicConfigManager) GetConfig(ctx context.Context, protoFilePath string) (configs.ConfigItem, error) {
|
||||
possiblePath := configs.ListConfigPaths(filepath.Dir(protoFilePath))
|
||||
for _, configFilePath := range possiblePath {
|
||||
items, err := b.loadConfig(configFilePath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
dir := filepath.Dir(configFilePath)
|
||||
for _, config := range items {
|
||||
for _, scope := range config.Config().Scopes {
|
||||
scopePath := filepath.Join(dir, scope)
|
||||
if strings.Contains(protoFilePath, scopePath) {
|
||||
return config, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil, errors.Errorf("unable to find config: %s", protoFilePath)
|
||||
}
|
||||
|
||||
func (b *BasicConfigManager) loadConfig(configFilePath string) ([]configs.ConfigItem, error) {
|
||||
b.treeLock.Lock()
|
||||
defer b.treeLock.Unlock()
|
||||
configItems, ok := b.tree[configFilePath]
|
||||
if !ok {
|
||||
fileInfo, err := os.Stat(configFilePath)
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
b.tree[configFilePath] = nil
|
||||
return nil, nil
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
if fileInfo.IsDir() {
|
||||
b.tree[configFilePath] = nil
|
||||
return nil, nil
|
||||
}
|
||||
data, err := configs.LoadConfigItems(configFilePath)
|
||||
if err != nil {
|
||||
return nil, errors.WithMessagef(err, "failed to decode: %s", configFilePath)
|
||||
}
|
||||
b.tree[configFilePath] = data
|
||||
return data, nil
|
||||
}
|
||||
return configItems, nil
|
||||
}
|
||||
43
pkg/component/pluginmanager/errors.go
Normal file
43
pkg/component/pluginmanager/errors.go
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
// Copyright 2021 storyicon@foxmail.com
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package pluginmanager
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/storyicon/powerproto/pkg/util/command"
|
||||
)
|
||||
|
||||
// ErrGoInstall defines the go install error
|
||||
type ErrGoInstall struct {
|
||||
*command.ErrCommandExec
|
||||
}
|
||||
|
||||
// ErrGoList defines the go list error
|
||||
type ErrGoList struct {
|
||||
*command.ErrCommandExec
|
||||
}
|
||||
|
||||
// ErrHTTPDownload defines the download error
|
||||
type ErrHTTPDownload struct {
|
||||
Url string
|
||||
Err error
|
||||
Code int
|
||||
}
|
||||
|
||||
// Error implements the error interface
|
||||
func (err *ErrHTTPDownload) Error() string {
|
||||
return fmt.Sprintf("failed to download %s, code: %d, err: %s", err.Url, err.Code, err.Err)
|
||||
}
|
||||
215
pkg/component/pluginmanager/manager.go
Normal file
215
pkg/component/pluginmanager/manager.go
Normal file
|
|
@ -0,0 +1,215 @@
|
|||
// Copyright 2021 storyicon@foxmail.com
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package pluginmanager
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"io/fs"
|
||||
"os"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/storyicon/powerproto/pkg/consts"
|
||||
"github.com/storyicon/powerproto/pkg/util"
|
||||
"github.com/storyicon/powerproto/pkg/util/logger"
|
||||
)
|
||||
|
||||
var defaultExecuteTimeout = time.Second * 60
|
||||
|
||||
// PluginManager is used to manage plugins
|
||||
type PluginManager interface {
|
||||
// GetPluginLatestVersion is used to get the latest version of plugin
|
||||
GetPluginLatestVersion(ctx context.Context, path string) (string, error)
|
||||
// ListPluginVersions is used to list the versions of plugin
|
||||
ListPluginVersions(ctx context.Context, path string) ([]string, error)
|
||||
// IsPluginInstalled is used to check whether the plugin is installed
|
||||
IsPluginInstalled(ctx context.Context, path string, version string) (bool, string, error)
|
||||
// InstallPlugin is used to install plugin
|
||||
InstallPlugin(ctx context.Context, path string, version string) (local string, err error)
|
||||
|
||||
// GetProtocLatestVersion is used to geet the latest version of protoc
|
||||
GetProtocLatestVersion(ctx context.Context) (string, error)
|
||||
// ListProtocVersions is used to list protoc version
|
||||
ListProtocVersions(ctx context.Context) ([]string, error)
|
||||
// IsProtocInstalled is used to check whether the protoc is installed
|
||||
IsProtocInstalled(ctx context.Context, version string) (bool, string, error)
|
||||
// InstallProtoc is used to install protoc of specified version
|
||||
InstallProtoc(ctx context.Context, version string) (local string, err error)
|
||||
// IncludePath returns the default include path
|
||||
IncludePath(ctx context.Context) string
|
||||
}
|
||||
|
||||
// Config defines the config of PluginManager
|
||||
type Config struct {
|
||||
StorageDir string `json:"storage"`
|
||||
}
|
||||
|
||||
// NewConfig is used to create config
|
||||
func NewConfig() *Config {
|
||||
return &Config{
|
||||
StorageDir: consts.GetHomeDir(),
|
||||
}
|
||||
}
|
||||
|
||||
// NewPluginManager is used to create PluginManager
|
||||
func NewPluginManager(cfg *Config, log logger.Logger) (PluginManager, error) {
|
||||
return NewBasicPluginManager(cfg.StorageDir, log)
|
||||
}
|
||||
|
||||
// BasicPluginManager is the basic implement of PluginManager
|
||||
type BasicPluginManager struct {
|
||||
logger.Logger
|
||||
storageDir string
|
||||
versions map[string][]string
|
||||
versionsLock sync.RWMutex
|
||||
}
|
||||
|
||||
// NewBasicPluginManager is used to create basic PluginManager
|
||||
func NewBasicPluginManager(storageDir string, log logger.Logger) (*BasicPluginManager, error) {
|
||||
return &BasicPluginManager{
|
||||
Logger: log.NewLogger("pluginmanager"),
|
||||
storageDir: storageDir,
|
||||
versions: map[string][]string{},
|
||||
}, nil
|
||||
}
|
||||
|
||||
// GetPluginLatestVersion is used to get the latest version of plugin
|
||||
func (b *BasicPluginManager) GetPluginLatestVersion(ctx context.Context, path string) (string, error) {
|
||||
versions, err := b.ListPluginVersions(ctx, path)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if len(versions) == 0 {
|
||||
return "", errors.New("no version list")
|
||||
}
|
||||
return versions[len(versions)-1], nil
|
||||
}
|
||||
|
||||
// ListPluginVersions is used to list the versions of plugin
|
||||
func (b *BasicPluginManager) ListPluginVersions(ctx context.Context, path string) ([]string, error) {
|
||||
ctx, cancel := context.WithTimeout(ctx, defaultExecuteTimeout)
|
||||
defer cancel()
|
||||
|
||||
b.versionsLock.RLock()
|
||||
versions, ok := b.versions[path]
|
||||
b.versionsLock.RUnlock()
|
||||
if ok {
|
||||
return versions, nil
|
||||
}
|
||||
versions, err := ListsGoPackageVersionsAmbiguously(ctx, b.Logger, path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b.versionsLock.Lock()
|
||||
b.versions[path] = versions
|
||||
b.versionsLock.Unlock()
|
||||
return versions, nil
|
||||
}
|
||||
|
||||
// IsPluginInstalled is used to check whether the plugin is installed
|
||||
func (b *BasicPluginManager) IsPluginInstalled(ctx context.Context, path string, version string) (bool, string, error) {
|
||||
return IsPluginInstalled(ctx, b.storageDir, path, version)
|
||||
}
|
||||
|
||||
// InstallPlugin is used to install plugin
|
||||
func (b *BasicPluginManager) InstallPlugin(ctx context.Context, path string, version string) (local string, err error) {
|
||||
return InstallPluginUsingGo(ctx, b.Logger, b.storageDir, path, version)
|
||||
}
|
||||
|
||||
// GetProtocLatestVersion is used to geet the latest version of protoc
|
||||
func (b *BasicPluginManager) GetProtocLatestVersion(ctx context.Context) (string, error) {
|
||||
versions, err := b.ListProtocVersions(ctx)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if len(versions) == 0 {
|
||||
return "", errors.New("no version list")
|
||||
}
|
||||
return versions[len(versions)-1], nil
|
||||
}
|
||||
|
||||
// ListProtocVersions is used to list protoc version
|
||||
func (b *BasicPluginManager) ListProtocVersions(ctx context.Context) ([]string, error) {
|
||||
ctx, cancel := context.WithTimeout(ctx, defaultExecuteTimeout)
|
||||
defer cancel()
|
||||
|
||||
b.versionsLock.RLock()
|
||||
versions, ok := b.versions["protoc"]
|
||||
b.versionsLock.RUnlock()
|
||||
if ok {
|
||||
return versions, nil
|
||||
}
|
||||
versions, err := ListGitTags(ctx, b.Logger, consts.ProtobufRepository)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b.versionsLock.Lock()
|
||||
b.versions["protoc"] = versions
|
||||
b.versionsLock.Unlock()
|
||||
return versions, nil
|
||||
}
|
||||
|
||||
// IsProtocInstalled is used to check whether the protoc is installed
|
||||
func (b *BasicPluginManager) IsProtocInstalled(ctx context.Context, version string) (bool, string, error) {
|
||||
if strings.HasPrefix(version, "v") {
|
||||
version = strings.TrimPrefix(version, "v")
|
||||
}
|
||||
return IsProtocInstalled(ctx, b.storageDir, version)
|
||||
}
|
||||
|
||||
// InstallProtoc is used to install protoc of specified version
|
||||
func (b *BasicPluginManager) InstallProtoc(ctx context.Context, version string) (string, error) {
|
||||
ctx, cancel := context.WithTimeout(ctx, defaultExecuteTimeout)
|
||||
defer cancel()
|
||||
|
||||
if strings.HasPrefix(version, "v") {
|
||||
version = strings.TrimPrefix(version, "v")
|
||||
}
|
||||
local := PathForProtoc(b.storageDir, version)
|
||||
exists, err := util.IsFileExists(local)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if exists {
|
||||
return local, nil
|
||||
}
|
||||
|
||||
release, err := GetProtocRelease(ctx, version)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer release.Clear()
|
||||
// merge include files
|
||||
includeDir := PathForInclude(b.storageDir)
|
||||
if err := util.CopyDirectory(release.GetIncludePath(), includeDir); err != nil {
|
||||
return "", err
|
||||
}
|
||||
// download protoc file
|
||||
if err := util.CopyFile(release.GetProtocPath(), local); err != nil {
|
||||
return "", err
|
||||
}
|
||||
// * it is required on unix system
|
||||
if err := os.Chmod(local, fs.ModePerm); err != nil {
|
||||
return "", err
|
||||
}
|
||||
return local, nil
|
||||
}
|
||||
|
||||
// IncludePath returns the default include path
|
||||
func (b *BasicPluginManager) IncludePath(ctx context.Context) string {
|
||||
return PathForInclude(b.storageDir)
|
||||
}
|
||||
92
pkg/component/pluginmanager/paths.go
Normal file
92
pkg/component/pluginmanager/paths.go
Normal file
|
|
@ -0,0 +1,92 @@
|
|||
// Copyright 2021 storyicon@foxmail.com
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package pluginmanager
|
||||
|
||||
import (
|
||||
"path"
|
||||
"path/filepath"
|
||||
|
||||
"golang.org/x/mod/module"
|
||||
|
||||
"github.com/storyicon/powerproto/pkg/util"
|
||||
)
|
||||
|
||||
|
||||
// PathForInclude is used to get the local directory of include files
|
||||
func PathForInclude(storageDir string) string {
|
||||
return filepath.Join(storageDir, "include")
|
||||
}
|
||||
|
||||
// PathForProtoc is used to get the local binary location where the specified version protoc should be stored
|
||||
func PathForProtoc(storageDir string, version string) string {
|
||||
return filepath.Join(storageDir, "protoc", version, util.GetBinaryFileName("protoc"))
|
||||
}
|
||||
|
||||
// GetPluginPath is used to get the plugin path
|
||||
func GetPluginPath(path string, version string) (string, error) {
|
||||
enc, err := module.EscapePath(path)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
encVer, err := module.EscapeVersion(version)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return filepath.Join(enc + "@" + encVer), nil
|
||||
}
|
||||
|
||||
// PathForPluginDir is used to get the local directory where the specified version plug-in should be stored
|
||||
func PathForPluginDir(storageDir string, path string, version string) (string, error) {
|
||||
pluginPath, err := GetPluginPath(path, version)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return filepath.Join(storageDir, "plugins", pluginPath), nil
|
||||
}
|
||||
|
||||
// PathForPlugin is used to get the binary path of plugin
|
||||
func PathForPlugin(storageDir string, path string, version string) (string, error) {
|
||||
name := GetGoPkgExecName(path)
|
||||
dir, err := PathForPluginDir(storageDir, path, version)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return filepath.Join(dir, util.GetBinaryFileName(name)), nil
|
||||
}
|
||||
|
||||
// isVersionElement reports whether s is a well-formed path version element:
|
||||
// v2, v3, v10, etc, but not v0, v05, v1.
|
||||
// `src\cmd\go\internal\load\pkg.go:1209`
|
||||
func isVersionElement(s string) bool {
|
||||
if len(s) < 2 || s[0] != 'v' || s[1] == '0' || s[1] == '1' && len(s) == 2 {
|
||||
return false
|
||||
}
|
||||
for i := 1; i < len(s); i++ {
|
||||
if s[i] < '0' || '9' < s[i] {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// GetGoPkgExecName is used to parse binary name from pkg uri
|
||||
// `src\cmd\go\internal\load\pkg.go:1595`
|
||||
func GetGoPkgExecName(pkgPath string) string {
|
||||
_, elem := path.Split(pkgPath)
|
||||
if elem != pkgPath && isVersionElement(elem) {
|
||||
_, elem = path.Split(path.Dir(pkgPath))
|
||||
}
|
||||
return elem
|
||||
}
|
||||
174
pkg/component/pluginmanager/plugin.go
Normal file
174
pkg/component/pluginmanager/plugin.go
Normal file
|
|
@ -0,0 +1,174 @@
|
|||
// Copyright 2021 storyicon@foxmail.com
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package pluginmanager
|
||||
|
||||
import (
|
||||
"context"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/hashicorp/go-multierror"
|
||||
jsoniter "github.com/json-iterator/go"
|
||||
|
||||
"github.com/storyicon/powerproto/pkg/util"
|
||||
"github.com/storyicon/powerproto/pkg/util/command"
|
||||
"github.com/storyicon/powerproto/pkg/util/logger"
|
||||
)
|
||||
|
||||
// IsPluginInstalled is used to check whether a plugin is installed
|
||||
func IsPluginInstalled(ctx context.Context,
|
||||
storageDir string,
|
||||
path string, version string) (bool, string, error) {
|
||||
local, err := PathForPlugin(storageDir, path, version)
|
||||
if err != nil {
|
||||
return false, "", err
|
||||
}
|
||||
exists, err := util.IsFileExists(local)
|
||||
if err != nil {
|
||||
return false, "", err
|
||||
}
|
||||
if exists {
|
||||
return true, local, nil
|
||||
}
|
||||
return false, "", nil
|
||||
}
|
||||
|
||||
// InstallPluginUsingGo is used to install plugin using golang
|
||||
func InstallPluginUsingGo(ctx context.Context,
|
||||
log logger.Logger,
|
||||
storageDir string,
|
||||
path string, version string) (string, error) {
|
||||
exists, local, err := IsPluginInstalled(ctx, storageDir, path, version)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if exists {
|
||||
return local, nil
|
||||
}
|
||||
|
||||
local, err = PathForPlugin(storageDir, path, version)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
dir := filepath.Dir(local)
|
||||
|
||||
uri := util.JoinGoPackageVersion(path, version)
|
||||
_, err2 := command.Execute(ctx, log, "", "go", []string{
|
||||
"install", uri,
|
||||
}, []string{"GOBIN=" + dir, "GO111MODULE=on"})
|
||||
if err2 != nil {
|
||||
return "", &ErrGoInstall{
|
||||
ErrCommandExec: err2,
|
||||
}
|
||||
}
|
||||
return local, nil
|
||||
}
|
||||
|
||||
// ///////////////// Version Control /////////////////
|
||||
|
||||
// Module defines the model of go list data
|
||||
type Module struct {
|
||||
Path string // module path
|
||||
Version string // module version
|
||||
Versions []string // available module versions (with -versions)
|
||||
Replace *Module // replaced by this module
|
||||
Time *time.Time // time version was created
|
||||
Update *Module // available update, if any (with -u)
|
||||
Main bool // is this the main module?
|
||||
Indirect bool // is this module only an indirect dependency of main module?
|
||||
Dir string // directory holding files for this module, if any
|
||||
GoMod string // path to go.mod file used when loading this module, if any
|
||||
GoVersion string // go version used in module
|
||||
Retracted string // retraction information, if any (with -retracted or -u)
|
||||
Error *ModuleError // error loading module
|
||||
}
|
||||
|
||||
// ModuleError defines the module error
|
||||
type ModuleError struct {
|
||||
Err string // the error itself
|
||||
}
|
||||
|
||||
// ListGoPackageVersions is list go package versions
|
||||
func ListGoPackageVersions(ctx context.Context, log logger.Logger, path string) ([]string, error) {
|
||||
// query from latest version
|
||||
// If latest is not specified here, the queried version
|
||||
// may be restricted to the current project go.mod/go.sum
|
||||
pkg := util.JoinGoPackageVersion(path, "latest")
|
||||
data, err := command.Execute(ctx, log, "", "go", []string{
|
||||
"list", "-m", "-json", "-versions", pkg,
|
||||
}, []string{
|
||||
"GO111MODULE=on",
|
||||
})
|
||||
if err != nil {
|
||||
return nil, &ErrGoList{
|
||||
ErrCommandExec: err,
|
||||
}
|
||||
}
|
||||
var module Module
|
||||
if err := jsoniter.Unmarshal(data, &module); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(module.Versions) != 0 {
|
||||
return module.Versions, nil
|
||||
}
|
||||
return []string{module.Version}, nil
|
||||
}
|
||||
|
||||
// ListsGoPackageVersionsAmbiguously is used to list go package versions ambiguously
|
||||
func ListsGoPackageVersionsAmbiguously(ctx context.Context, log logger.Logger, pkg string) ([]string, error) {
|
||||
type Result struct {
|
||||
err error
|
||||
pkg string
|
||||
versions []string
|
||||
}
|
||||
items := strings.Split(pkg, "/")
|
||||
dataMap := make([]*Result, len(items))
|
||||
notify := make(chan struct{}, 1)
|
||||
maxIndex := len(items) - 1
|
||||
for i := maxIndex; i >= 1; i-- {
|
||||
go func(i int) {
|
||||
pkg := strings.Join(items[0:i+1], "/")
|
||||
versions, err := ListGoPackageVersions(context.TODO(), log, pkg)
|
||||
dataMap[maxIndex-i] = &Result{
|
||||
pkg: pkg,
|
||||
versions: versions,
|
||||
err: err,
|
||||
}
|
||||
notify <- struct{}{}
|
||||
}(i)
|
||||
}
|
||||
OutLoop:
|
||||
for {
|
||||
select {
|
||||
case <-notify:
|
||||
var errs error
|
||||
for _, data := range dataMap {
|
||||
if data == nil {
|
||||
continue OutLoop
|
||||
}
|
||||
if data.err != nil {
|
||||
errs = multierror.Append(errs, data.err)
|
||||
}
|
||||
if data.versions != nil {
|
||||
return data.versions, nil
|
||||
}
|
||||
}
|
||||
return nil, errs
|
||||
case <-ctx.Done():
|
||||
return nil, ctx.Err()
|
||||
}
|
||||
}
|
||||
}
|
||||
27
pkg/component/pluginmanager/pluginmanager_suite_test.go
Normal file
27
pkg/component/pluginmanager/pluginmanager_suite_test.go
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
// Copyright 2021 storyicon@foxmail.com
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package pluginmanager_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
)
|
||||
|
||||
func TestPluginmanager(t *testing.T) {
|
||||
RegisterFailHandler(Fail)
|
||||
RunSpecs(t, "Pluginmanager Suite")
|
||||
}
|
||||
73
pkg/component/pluginmanager/pluginmanager_test.go
Normal file
73
pkg/component/pluginmanager/pluginmanager_test.go
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
// Copyright 2021 storyicon@foxmail.com
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package pluginmanager_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"path/filepath"
|
||||
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
|
||||
"github.com/storyicon/powerproto/pkg/component/pluginmanager"
|
||||
"github.com/storyicon/powerproto/pkg/util/logger"
|
||||
)
|
||||
|
||||
var _ = Describe("Pluginmanager", func() {
|
||||
cfg := pluginmanager.NewConfig()
|
||||
cfg.StorageDir, _ = filepath.Abs("./tests")
|
||||
|
||||
const pluginPkg = "google.golang.org/protobuf/cmd/protoc-gen-go"
|
||||
var manager pluginmanager.PluginManager
|
||||
It("should able to init", func() {
|
||||
pluginManager, err := pluginmanager.NewPluginManager(cfg, logger.NewDefault("pluginmanager"))
|
||||
Expect(err).To(BeNil())
|
||||
Expect(pluginManager).To(Not(BeNil()))
|
||||
manager = pluginManager
|
||||
})
|
||||
It("should able to install protoc", func() {
|
||||
versions, err := manager.ListProtocVersions(context.TODO())
|
||||
Expect(err).To(BeNil())
|
||||
Expect(len(versions) > 0).To(BeTrue())
|
||||
latestVersion, err := manager.GetProtocLatestVersion(context.TODO())
|
||||
Expect(err).To(BeNil())
|
||||
Expect(latestVersion).To(Equal(versions[len(versions)-1]))
|
||||
|
||||
local, err := manager.InstallProtoc(context.TODO(), latestVersion)
|
||||
Expect(err).To(BeNil())
|
||||
exists, local, err := manager.IsProtocInstalled(context.TODO(), latestVersion)
|
||||
Expect(err).To(BeNil())
|
||||
Expect(exists).To(BeTrue())
|
||||
Expect(len(local) != 0).To(BeTrue())
|
||||
})
|
||||
It("should able to install plugin", func() {
|
||||
versions, err := manager.ListPluginVersions(context.TODO(), pluginPkg)
|
||||
Expect(err).To(BeNil())
|
||||
Expect(len(versions) > 0).To(BeTrue())
|
||||
|
||||
latestVersion, err := manager.GetPluginLatestVersion(context.TODO(), pluginPkg)
|
||||
Expect(err).To(BeNil())
|
||||
Expect(latestVersion).To(Equal(versions[len(versions)-1]))
|
||||
|
||||
local, err := manager.InstallPlugin(context.TODO(), pluginPkg, latestVersion)
|
||||
Expect(err).To(BeNil())
|
||||
Expect(len(local) > 0).To(BeTrue())
|
||||
|
||||
exists, local, err := manager.IsPluginInstalled(context.TODO(), pluginPkg, latestVersion)
|
||||
Expect(err).To(BeNil())
|
||||
Expect(exists).To(BeTrue())
|
||||
Expect(len(local) != 0).To(BeTrue())
|
||||
})
|
||||
})
|
||||
186
pkg/component/pluginmanager/protoc.go
Normal file
186
pkg/component/pluginmanager/protoc.go
Normal file
|
|
@ -0,0 +1,186 @@
|
|||
// Copyright 2021 storyicon@foxmail.com
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package pluginmanager
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/fs"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
"github.com/mholt/archiver"
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/storyicon/powerproto/pkg/util"
|
||||
"github.com/storyicon/powerproto/pkg/util/command"
|
||||
"github.com/storyicon/powerproto/pkg/util/logger"
|
||||
)
|
||||
|
||||
// ProtocRelease defines the release of protoc
|
||||
type ProtocRelease struct {
|
||||
workspace string
|
||||
}
|
||||
|
||||
// GetIncludePath is used to get the include path
|
||||
func (p *ProtocRelease) GetIncludePath() string {
|
||||
return filepath.Join(p.workspace, "include")
|
||||
}
|
||||
|
||||
// GetProtocPath is used to get the protoc path
|
||||
func (p *ProtocRelease) GetProtocPath() string {
|
||||
return filepath.Join(p.workspace, "bin", util.GetBinaryFileName("protoc"))
|
||||
}
|
||||
|
||||
// Clear is used to clear the workspace
|
||||
func (p *ProtocRelease) Clear() error {
|
||||
return os.RemoveAll(p.workspace)
|
||||
}
|
||||
|
||||
// GetProtocRelease is used to download protoc release
|
||||
func GetProtocRelease(ctx context.Context, version string) (*ProtocRelease, error) {
|
||||
workspace, err := os.MkdirTemp("", "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
suffix, err := inferProtocReleaseSuffix()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
filename := fmt.Sprintf("protoc-%s-%s.zip", version, suffix)
|
||||
url := fmt.Sprintf("https://github.com/protocolbuffers/protobuf/"+
|
||||
"releases/download/v%s/%s", version, filename)
|
||||
req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
|
||||
if err != nil {
|
||||
return nil, &ErrHTTPDownload{
|
||||
Url: url,
|
||||
Err: err,
|
||||
}
|
||||
}
|
||||
resp, err := http.DefaultClient.Do(req)
|
||||
if err != nil {
|
||||
return nil, &ErrHTTPDownload{
|
||||
Url: url,
|
||||
Err: err,
|
||||
}
|
||||
}
|
||||
zipFilePath := filepath.Join(workspace, filename)
|
||||
if err := downloadFile(resp, zipFilePath); err != nil {
|
||||
return nil, &ErrHTTPDownload{
|
||||
Url: url,
|
||||
Err: err,
|
||||
Code: resp.StatusCode,
|
||||
}
|
||||
}
|
||||
zip := archiver.NewZip()
|
||||
if err := zip.Unarchive(zipFilePath, workspace); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &ProtocRelease{
|
||||
workspace: workspace,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// IsProtocInstalled is used to check whether the protoc version is installed
|
||||
func IsProtocInstalled(ctx context.Context, storageDir string, version string) (bool, string, error) {
|
||||
local := PathForProtoc(storageDir, version)
|
||||
exists, err := util.IsFileExists(local)
|
||||
if err != nil {
|
||||
return false, "", err
|
||||
}
|
||||
return exists, local, nil
|
||||
}
|
||||
|
||||
// ErrGitList defines the git list error
|
||||
type ErrGitList struct {
|
||||
*command.ErrCommandExec
|
||||
}
|
||||
|
||||
// ListGitTags is used to list the git tags of specified repository
|
||||
func ListGitTags(ctx context.Context, log logger.Logger, repo string) ([]string, error) {
|
||||
data, err := command.Execute(ctx, log, "", "git", []string{
|
||||
"ls-remote", "--tags", "--refs", "--sort", "version:refname", repo,
|
||||
}, nil)
|
||||
if err != nil {
|
||||
return nil, &ErrGitList{
|
||||
ErrCommandExec: err,
|
||||
}
|
||||
}
|
||||
var tags []string
|
||||
for _, line := range strings.Split(string(data), "\n") {
|
||||
f := strings.Fields(line)
|
||||
if len(f) != 2 {
|
||||
continue
|
||||
}
|
||||
if strings.HasPrefix(f[1], "refs/tags/") {
|
||||
tags = append(tags, strings.TrimPrefix(f[1], "refs/tags/"))
|
||||
}
|
||||
}
|
||||
return tags, nil
|
||||
}
|
||||
|
||||
func inferProtocReleaseSuffix() (string, error) {
|
||||
goos := strings.ToLower(runtime.GOOS)
|
||||
arch := strings.ToLower(runtime.GOARCH)
|
||||
switch goos {
|
||||
case "linux":
|
||||
switch arch {
|
||||
case "arm64":
|
||||
return "linux-aarch_64", nil
|
||||
case "ppc64le":
|
||||
return "linux-ppcle_64", nil
|
||||
case "s390x":
|
||||
return "linux-s390_64", nil
|
||||
case "386":
|
||||
return "linux-x86_32", nil
|
||||
case "amd64":
|
||||
return "linux-x86_64", nil
|
||||
}
|
||||
case "darwin":
|
||||
return "osx-x86_64", nil
|
||||
case "windows":
|
||||
switch arch {
|
||||
case "386":
|
||||
return "win32", nil
|
||||
case "amd64":
|
||||
return "win64", nil
|
||||
}
|
||||
}
|
||||
return "", errors.New("protoc did not release on this platform")
|
||||
}
|
||||
|
||||
func downloadFile(resp *http.Response, destination string) error {
|
||||
if err := os.MkdirAll(filepath.Dir(destination), fs.ModePerm); err != nil {
|
||||
return err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
if resp.StatusCode != 200 {
|
||||
return errors.Errorf("unexpected code %d for url: %s", resp.StatusCode, resp.Request.URL.String())
|
||||
}
|
||||
file, err := os.OpenFile(destination, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, fs.ModePerm)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer file.Close()
|
||||
_, err = io.Copy(file, resp.Body)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
109
pkg/configs/configs.go
Normal file
109
pkg/configs/configs.go
Normal file
|
|
@ -0,0 +1,109 @@
|
|||
// Copyright 2021 storyicon@foxmail.com
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package configs
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io/fs"
|
||||
"io/ioutil"
|
||||
"path/filepath"
|
||||
|
||||
"gopkg.in/yaml.v3"
|
||||
|
||||
"github.com/storyicon/powerproto/pkg/consts"
|
||||
"github.com/storyicon/powerproto/pkg/util"
|
||||
)
|
||||
|
||||
// Config defines the config model
|
||||
type Config struct {
|
||||
Scopes []string `json:"scopes" yaml:"scopes"`
|
||||
Protoc string `json:"protoc" yaml:"protoc"`
|
||||
ProtocWorkDir string `json:"protocWorkDir" yaml:"protocWorkDir"`
|
||||
Plugins map[string]string `json:"plugins" yaml:"plugins"`
|
||||
Options []string `json:"options" yaml:"options"`
|
||||
ImportPaths []string `json:"importPaths" yaml:"importPaths"`
|
||||
PostActions []*PostAction `json:"postActions" yaml:"postActions"`
|
||||
PostShell string `json:"postShell" yaml:"postShell"`
|
||||
}
|
||||
|
||||
// PostAction defines the Action model
|
||||
type PostAction struct {
|
||||
Name string `json:"name" yaml:"name"`
|
||||
Args []string `json:"args" yaml:"args"`
|
||||
}
|
||||
|
||||
// SaveConfigs is used to save configs into files
|
||||
func SaveConfigs(path string, configs ...*Config) error {
|
||||
parts := make([][]byte, 0, len(configs))
|
||||
for _, config := range configs {
|
||||
data, err := yaml.Marshal(config)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
parts = append(parts, data)
|
||||
}
|
||||
data := bytes.Join(parts, []byte("\r\n---\r\n"))
|
||||
if err := ioutil.WriteFile(path, data, fs.ModePerm); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// LoadConfigs is used to load config from specified path
|
||||
func LoadConfigs(path string) ([]*Config, error) {
|
||||
raw, err := ioutil.ReadFile(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
items, err := util.SplitYAML(raw)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var ret []*Config
|
||||
for _, item := range items {
|
||||
var config Config
|
||||
if err := yaml.Unmarshal(item, &config); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ret = append(ret, &config)
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
// Similar to LoadConfigs, but obtains the abstraction of the Config prototype structure
|
||||
func LoadConfigItems(path string) ([]ConfigItem, error) {
|
||||
data, err := LoadConfigs(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return GetConfigItems(data, path), nil
|
||||
}
|
||||
|
||||
// ListConfigPaths is used to list all possible config paths
|
||||
func ListConfigPaths(sourceDir string) []string {
|
||||
var paths []string
|
||||
cur := sourceDir
|
||||
for {
|
||||
filePath := filepath.Join(cur, consts.ConfigFileName)
|
||||
paths = append(paths, filePath)
|
||||
next := filepath.Dir(cur)
|
||||
if next == cur {
|
||||
break
|
||||
}
|
||||
cur = next
|
||||
}
|
||||
paths = append(paths, consts.PathForGlobalConfig())
|
||||
return paths
|
||||
}
|
||||
67
pkg/configs/item.go
Normal file
67
pkg/configs/item.go
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
// Copyright 2021 storyicon@foxmail.com
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package configs
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// ConfigItem is the wrapper of Config
|
||||
type ConfigItem interface {
|
||||
// ID is used to return to config unique id
|
||||
ID() string
|
||||
// Path is used to return the config path
|
||||
Path() string
|
||||
// Config is used to return the Config
|
||||
Config() *Config
|
||||
}
|
||||
|
||||
// GetConfigs is used to generate Config from given config entity
|
||||
func GetConfigItems(data []*Config, path string) []ConfigItem {
|
||||
ret := make([]ConfigItem, 0, len(data))
|
||||
for i, item := range data {
|
||||
ret = append(ret, newConfigItem(item, path, i))
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
type configItem struct {
|
||||
id string
|
||||
c *Config
|
||||
path string
|
||||
}
|
||||
|
||||
// ID is used to return to config unique id
|
||||
func (c *configItem) ID() string {
|
||||
return c.id
|
||||
}
|
||||
|
||||
// Path is used to return the config path
|
||||
func (c *configItem) Path() string {
|
||||
return c.path
|
||||
}
|
||||
|
||||
// Config is used to return the Config
|
||||
func (c *configItem) Config() *Config {
|
||||
return c.c
|
||||
}
|
||||
|
||||
func newConfigItem(c *Config, path string, idx int) ConfigItem {
|
||||
return &configItem{
|
||||
id: fmt.Sprintf("%s:%d", path, idx),
|
||||
c: c,
|
||||
path: path,
|
||||
}
|
||||
}
|
||||
69
pkg/consts/consts.go
Normal file
69
pkg/consts/consts.go
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
// Copyright 2021 storyicon@foxmail.com
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package consts
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/storyicon/powerproto/pkg/util/logger"
|
||||
)
|
||||
|
||||
|
||||
// defines a set of const value
|
||||
const (
|
||||
// ConfigFileName defines the config file name
|
||||
ConfigFileName = "powerproto.yaml"
|
||||
// The default include can be referenced by this key in import paths
|
||||
KeyPowerProtoInclude = "$POWERPROTO_INCLUDE"
|
||||
// Defines the program directory of PowerProto, including various binary and include files
|
||||
EnvHomeDir = "POWERPROTO_HOME"
|
||||
// ProtobufRepository defines the protobuf repository
|
||||
ProtobufRepository = "https://github.com/protocolbuffers/protobuf"
|
||||
)
|
||||
|
||||
var homeDir string
|
||||
var log = logger.NewDefault("consts")
|
||||
|
||||
// GetHomeDir is used to get cached homeDir
|
||||
func GetHomeDir() string {
|
||||
return homeDir
|
||||
}
|
||||
|
||||
// PathForGlobalConfig is used to get path of global config
|
||||
func PathForGlobalConfig() string {
|
||||
return filepath.Join(GetHomeDir(), ConfigFileName)
|
||||
}
|
||||
|
||||
func getHomeDir() (string, error) {
|
||||
val := os.Getenv(EnvHomeDir)
|
||||
if val != "" {
|
||||
return filepath.Abs(val)
|
||||
}
|
||||
homeDir, err := os.UserHomeDir()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return filepath.Join(homeDir, ".powerproto"), nil
|
||||
}
|
||||
|
||||
func init() {
|
||||
var err error
|
||||
homeDir, err = getHomeDir()
|
||||
if err != nil {
|
||||
log.LogFatal(nil, "Please set the working directory of PowerProto by "+
|
||||
"configuring the environment variable %s", EnvHomeDir)
|
||||
}
|
||||
}
|
||||
109
pkg/util/command/command.go
Normal file
109
pkg/util/command/command.go
Normal file
|
|
@ -0,0 +1,109 @@
|
|||
// Copyright 2021 storyicon@foxmail.com
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package command
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
|
||||
"github.com/storyicon/powerproto/pkg/util"
|
||||
"github.com/storyicon/powerproto/pkg/util/logger"
|
||||
)
|
||||
|
||||
type dryRun struct{}
|
||||
type ignoreDryRun struct{}
|
||||
type disableAction struct{}
|
||||
|
||||
// WithIgnoreDryRun is used to inject ignore dryRun flag into context
|
||||
func WithIgnoreDryRun(ctx context.Context) context.Context {
|
||||
return context.WithValue(ctx, ignoreDryRun{}, "true")
|
||||
}
|
||||
|
||||
// WithDisableAction is used to disable post action/shell
|
||||
func WithDisableAction(ctx context.Context) context.Context {
|
||||
return context.WithValue(ctx, disableAction{}, "true")
|
||||
}
|
||||
|
||||
// WithDryRun is used to inject dryRun flag into context
|
||||
func WithDryRun(ctx context.Context) context.Context {
|
||||
return context.WithValue(ctx, dryRun{}, "true")
|
||||
}
|
||||
|
||||
// IsDisableAction is used to decide whether to disable PostAction and PostShell
|
||||
func IsDisableAction(ctx context.Context) bool {
|
||||
return ctx.Value(disableAction{}) != nil
|
||||
}
|
||||
|
||||
// IsIgnoreDryRun is used to determine whether it is currently in ignore DryRun mode
|
||||
func IsIgnoreDryRun(ctx context.Context) bool {
|
||||
return ctx.Value(ignoreDryRun{}) != nil
|
||||
}
|
||||
|
||||
// IsDryRun is used to determine whether it is currently in DryRun mode
|
||||
func IsDryRun(ctx context.Context) bool {
|
||||
return ctx.Value(dryRun{}) != nil
|
||||
}
|
||||
|
||||
// Execute is used to execute commands, return stdout and execute errors
|
||||
func Execute(ctx context.Context,
|
||||
log logger.Logger,
|
||||
dir string, name string, arguments []string, env []string) ([]byte, *ErrCommandExec) {
|
||||
cmd := exec.CommandContext(ctx, name, arguments...)
|
||||
cmd.Env = append(os.Environ(), env...)
|
||||
cmd.Dir = dir
|
||||
|
||||
if IsDryRun(ctx) && !IsIgnoreDryRun(ctx) {
|
||||
log.LogInfo(map[string]interface{}{
|
||||
"command": cmd.String(),
|
||||
"dir": cmd.Dir,
|
||||
}, "DryRun")
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
var stdout, stderr bytes.Buffer
|
||||
cmd.Stdout = &stdout
|
||||
cmd.Stderr = &stderr
|
||||
if err := cmd.Run(); err != nil {
|
||||
return nil, &ErrCommandExec{
|
||||
Err: err,
|
||||
Dir: cmd.Dir,
|
||||
Command: cmd.String(),
|
||||
ExitCode: util.GetExitCode(err),
|
||||
Stdout: stdout.String(),
|
||||
Stderr: stderr.String(),
|
||||
}
|
||||
}
|
||||
return stdout.Bytes(), nil
|
||||
}
|
||||
|
||||
// ErrCommandExec defines the command error
|
||||
type ErrCommandExec struct {
|
||||
Err error
|
||||
Dir string
|
||||
Command string
|
||||
ExitCode int
|
||||
Stdout string
|
||||
Stderr string
|
||||
}
|
||||
|
||||
// Error implements the error interface
|
||||
func (err *ErrCommandExec) Error() string {
|
||||
return fmt.Sprintf("failed to execute %s in %s, stderr: %s, exit code %d, %s",
|
||||
err.Command, err.Dir, err.Stderr, err.ExitCode, err.Err,
|
||||
)
|
||||
}
|
||||
27
pkg/util/command/command_suite_test.go
Normal file
27
pkg/util/command/command_suite_test.go
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
// Copyright 2021 storyicon@foxmail.com
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package command_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
)
|
||||
|
||||
func TestCommand(t *testing.T) {
|
||||
RegisterFailHandler(Fail)
|
||||
RunSpecs(t, "Command Suite")
|
||||
}
|
||||
38
pkg/util/command/command_test.go
Normal file
38
pkg/util/command/command_test.go
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
// Copyright 2021 storyicon@foxmail.com
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package command_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
|
||||
"github.com/storyicon/powerproto/pkg/util/command"
|
||||
)
|
||||
|
||||
var _ = Describe("Command", func() {
|
||||
ctx := context.Background()
|
||||
It("should able to dryRun", func() {
|
||||
Expect(command.IsDryRun(ctx)).To(BeFalse())
|
||||
ctx = command.WithDryRun(ctx)
|
||||
Expect(command.IsDryRun(ctx)).To(BeTrue())
|
||||
})
|
||||
It("should able to ignore dryRun", func() {
|
||||
Expect(command.IsIgnoreDryRun(ctx)).To(BeFalse())
|
||||
ctx = command.WithIgnoreDryRun(ctx)
|
||||
Expect(command.IsIgnoreDryRun(ctx)).To(BeTrue())
|
||||
})
|
||||
})
|
||||
38
pkg/util/concurrent/buffer.go
Normal file
38
pkg/util/concurrent/buffer.go
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
// Copyright 2021 storyicon@foxmail.com
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package concurrent
|
||||
|
||||
import (
|
||||
"io"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// Buffer is goroutine safety buffer
|
||||
type Buffer struct {
|
||||
writer io.Writer
|
||||
mutex sync.Mutex
|
||||
}
|
||||
|
||||
// Write implements the io.Writer
|
||||
func (s *Buffer) Write(p []byte) (n int, err error) {
|
||||
s.mutex.Lock()
|
||||
defer s.mutex.Unlock()
|
||||
return s.writer.Write(p)
|
||||
}
|
||||
|
||||
// NewBuffer is used to create a new buffer
|
||||
func NewBuffer(writer io.Writer) io.Writer {
|
||||
return &Buffer{writer: writer}
|
||||
}
|
||||
72
pkg/util/concurrent/errgroup.go
Normal file
72
pkg/util/concurrent/errgroup.go
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
// Copyright 2021 storyicon@foxmail.com
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package concurrent
|
||||
|
||||
import (
|
||||
"context"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// ErrGroup is another ErrGroup implement
|
||||
type ErrGroup struct {
|
||||
ctx context.Context
|
||||
cancel context.CancelFunc
|
||||
limit chan struct{}
|
||||
|
||||
errOnce sync.Once
|
||||
err error
|
||||
|
||||
wg sync.WaitGroup
|
||||
}
|
||||
|
||||
// NewErrGroup is used to create a new ErrGroup
|
||||
func NewErrGroup(ctx context.Context, concurrency int) *ErrGroup {
|
||||
ctx, cancel := context.WithCancel(ctx)
|
||||
return &ErrGroup{
|
||||
ctx: ctx,
|
||||
cancel: cancel,
|
||||
limit: make(chan struct{}, concurrency),
|
||||
}
|
||||
}
|
||||
|
||||
// Wait is used to wait ErrGroup finish
|
||||
func (g *ErrGroup) Wait() error {
|
||||
g.wg.Wait()
|
||||
g.cancel()
|
||||
return g.err
|
||||
}
|
||||
|
||||
// Go is used to start a new goroutine
|
||||
func (g *ErrGroup) Go(f func(ctx context.Context) error) {
|
||||
if g.err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
g.limit <- struct{}{}
|
||||
g.wg.Add(1)
|
||||
go func() {
|
||||
defer func() {
|
||||
<-g.limit
|
||||
g.wg.Done()
|
||||
}()
|
||||
if err := f(g.ctx); err != nil {
|
||||
g.cancel()
|
||||
g.errOnce.Do(func() {
|
||||
g.err = err
|
||||
g.cancel()
|
||||
})
|
||||
}
|
||||
}()
|
||||
}
|
||||
131
pkg/util/file.go
Normal file
131
pkg/util/file.go
Normal file
|
|
@ -0,0 +1,131 @@
|
|||
// Copyright 2021 storyicon@foxmail.com
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package util
|
||||
|
||||
import (
|
||||
"io"
|
||||
"io/fs"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/bmatcuk/doublestar"
|
||||
filecopy "github.com/otiai10/copy"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// MatchPath is used to match path with specified pattern
|
||||
func MatchPath(pattern string, path string) (bool, error) {
|
||||
return doublestar.PathMatch(pattern, path)
|
||||
}
|
||||
|
||||
// CopyDirectory is used to copy directory
|
||||
// If dst already exists, it will be merged
|
||||
func CopyDirectory(src, dst string) error {
|
||||
return filecopy.Copy(src, dst)
|
||||
}
|
||||
|
||||
// CopyFile is used to copy file from src to dst
|
||||
func CopyFile(src, dst string) error {
|
||||
sourceFileStat, err := os.Stat(src)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !sourceFileStat.Mode().IsRegular() {
|
||||
return errors.Errorf("%s is not a regular file", src)
|
||||
}
|
||||
source, err := os.Open(src)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer source.Close()
|
||||
if err := os.MkdirAll(filepath.Dir(dst), fs.ModePerm); err != nil {
|
||||
return err
|
||||
}
|
||||
destination, err := os.Create(dst)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer destination.Close()
|
||||
_, err = io.Copy(destination, source)
|
||||
return err
|
||||
}
|
||||
|
||||
// IsFileExists is used to check whether the file exists
|
||||
func IsFileExists(path string) (bool, error) {
|
||||
info, err := os.Stat(path)
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
return false, nil
|
||||
}
|
||||
return false, err
|
||||
}
|
||||
if info.IsDir() {
|
||||
return false, errors.Errorf("%s is not a file", path)
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// IsDirExists is used to check whether the dir exists
|
||||
func IsDirExists(path string) (bool, error) {
|
||||
info, err := os.Stat(path)
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
return false, nil
|
||||
}
|
||||
return false, err
|
||||
}
|
||||
if !info.IsDir() {
|
||||
return false, errors.Errorf("%s is not a directory", path)
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// GetFilesWithExtRecursively is used to recursively list files with a specific suffix
|
||||
// expectExt should contain the prefix '.'
|
||||
func GetFilesWithExtRecursively(target string, targetExt string) ([]string, error) {
|
||||
var data []string
|
||||
err := filepath.Walk(target, func(path string, info fs.FileInfo, err error) error {
|
||||
if info.IsDir() {
|
||||
return nil
|
||||
}
|
||||
ext := filepath.Ext(path)
|
||||
if ext == targetExt {
|
||||
data = append(data, path)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
return data, err
|
||||
}
|
||||
|
||||
// GetFilesWithExtRecursively is used to list files with a specific suffix
|
||||
// expectExt should contain the prefix '.'
|
||||
func GetFilesWithExt(dir string, targetExt string) ([]string, error) {
|
||||
children, err := ioutil.ReadDir(dir)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var data []string
|
||||
for _, child := range children {
|
||||
if child.IsDir() {
|
||||
continue
|
||||
}
|
||||
if ext := filepath.Ext(child.Name()); ext != targetExt {
|
||||
continue
|
||||
}
|
||||
data = append(data, filepath.Join(dir, child.Name()))
|
||||
}
|
||||
return data, nil
|
||||
}
|
||||
217
pkg/util/logger/logger.go
Normal file
217
pkg/util/logger/logger.go
Normal file
|
|
@ -0,0 +1,217 @@
|
|||
// Copyright 2021 storyicon@foxmail.com
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package logger
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/fatih/color"
|
||||
jsoniter "github.com/json-iterator/go"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
)
|
||||
|
||||
// Logger defines the basic log library implementation
|
||||
type Logger interface {
|
||||
// LogDebug print a message with debug level.
|
||||
LogDebug(fields map[string]interface{}, format string, args ...interface{})
|
||||
// LogInfo print a message with info level.
|
||||
LogInfo(fields map[string]interface{}, format string, args ...interface{})
|
||||
// LogWarn print a message with warn level.
|
||||
LogWarn(fields map[string]interface{}, format string, args ...interface{})
|
||||
// LogError print a message with error level.
|
||||
LogError(fields map[string]interface{}, format string, args ...interface{})
|
||||
// LogFatal print a message with fatal level.
|
||||
LogFatal(fields map[string]interface{}, format string, args ...interface{})
|
||||
// NewLogger is used to derive a new child Logger
|
||||
NewLogger(component string) Logger
|
||||
// SetLogLevel is used to set log level
|
||||
SetLogLevel(level Level) Logger
|
||||
}
|
||||
|
||||
// BasicLogger simply implements Logger
|
||||
type BasicLogger struct {
|
||||
cfg *Config
|
||||
|
||||
component string
|
||||
registerer prometheus.Registerer
|
||||
}
|
||||
|
||||
// Config defines the config structure
|
||||
type Config struct {
|
||||
Pretty bool
|
||||
Level Level
|
||||
}
|
||||
|
||||
type Level struct {
|
||||
Name string
|
||||
Color color.Attribute
|
||||
Index int
|
||||
Writer io.Writer
|
||||
}
|
||||
|
||||
var (
|
||||
LevelDebug = Level{Name: "debug", Color: color.FgWhite, Index: 0, Writer: os.Stdout}
|
||||
LevelInfo = Level{Name: "info", Color: color.FgWhite, Index: 1, Writer: os.Stdout}
|
||||
LevelWarn = Level{Name: "warn", Color: color.FgYellow, Index: 2, Writer: os.Stderr}
|
||||
LevelError = Level{Name: "error", Color: color.FgHiRed, Index: 3, Writer: os.Stderr}
|
||||
LevelFatal = Level{Name: "fatal", Color: color.FgRed, Index: 4, Writer: os.Stderr}
|
||||
)
|
||||
|
||||
// NewConfig is used to init config with default values
|
||||
func NewConfig() *Config {
|
||||
return &Config{
|
||||
Pretty: false,
|
||||
Level: LevelDebug,
|
||||
}
|
||||
}
|
||||
|
||||
// NewDefault is used to initialize a simple Logger
|
||||
func NewDefault(component string) Logger {
|
||||
logger, err := New(NewConfig(), component, prometheus.DefaultRegisterer)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return logger
|
||||
}
|
||||
|
||||
// New is used to init service
|
||||
func New(cfg *Config, component string, registerer prometheus.Registerer) (Logger, error) {
|
||||
if cfg == nil {
|
||||
cfg = NewConfig()
|
||||
}
|
||||
service := &BasicLogger{
|
||||
cfg: cfg,
|
||||
component: component,
|
||||
registerer: registerer,
|
||||
}
|
||||
return service, nil
|
||||
}
|
||||
|
||||
// LogDebug print a message with debug level.
|
||||
func (b *BasicLogger) LogDebug(fields map[string]interface{}, format string, args ...interface{}) {
|
||||
b.log(LevelDebug, fields, format, args...)
|
||||
}
|
||||
|
||||
// LogInfo print a message with info level.
|
||||
func (b *BasicLogger) LogInfo(fields map[string]interface{}, format string, args ...interface{}) {
|
||||
b.log(LevelInfo, fields, format, args...)
|
||||
}
|
||||
|
||||
// LogWarn print a message with warn level.
|
||||
func (b *BasicLogger) LogWarn(fields map[string]interface{}, format string, args ...interface{}) {
|
||||
b.log(LevelWarn, fields, format, args...)
|
||||
}
|
||||
|
||||
// LogError print a message with error level.
|
||||
func (b *BasicLogger) LogError(fields map[string]interface{}, format string, args ...interface{}) {
|
||||
b.log(LevelError, fields, format, args...)
|
||||
}
|
||||
|
||||
// LogFatal print a message with fatal level.
|
||||
func (b *BasicLogger) LogFatal(fields map[string]interface{}, format string, args ...interface{}) {
|
||||
b.log(LevelFatal, fields, format, args...)
|
||||
}
|
||||
|
||||
// NewLogger is used to derive a new child Logger
|
||||
func (b *BasicLogger) NewLogger(component string) Logger {
|
||||
name := strings.Join([]string{b.component, component}, ".")
|
||||
logger, err := New(b.cfg, name, b.registerer)
|
||||
if err != nil {
|
||||
b.LogWarn(map[string]interface{}{
|
||||
"name": name,
|
||||
}, "failed to extend logger: %s", err)
|
||||
return b
|
||||
}
|
||||
return logger
|
||||
}
|
||||
|
||||
// SetLogLevel is used to set log level
|
||||
func (b *BasicLogger) SetLogLevel(level Level) Logger {
|
||||
b.cfg.Level = level
|
||||
return b
|
||||
}
|
||||
|
||||
func (b *BasicLogger) log(level Level, fields map[string]interface{}, format string, args ...interface{}) {
|
||||
if b.cfg.Level.Index > level.Index {
|
||||
return
|
||||
}
|
||||
if fields == nil {
|
||||
fields = map[string]interface{}{}
|
||||
}
|
||||
// if b.cfg.Level == LevelDebug {
|
||||
// if _, file, line, ok := runtime.Caller(4); ok {
|
||||
// fields["file"] = fmt.Sprintf("%s:%d", path.Base(file), line)
|
||||
// }
|
||||
// if b.component != "" {
|
||||
// fields["component"] = b.component
|
||||
// }
|
||||
// }
|
||||
if b.cfg.Pretty {
|
||||
dict := map[string]interface{}{}
|
||||
for key, val := range fields {
|
||||
dict[key] = val
|
||||
}
|
||||
dict["level"] = level.Name
|
||||
dict["message"] = fmt.Sprintf(format, args...)
|
||||
_ = jsoniter.NewEncoder(level.Writer).Encode(dict)
|
||||
return
|
||||
}
|
||||
var buf []byte
|
||||
buf = appendString(buf, fmt.Sprintf(format, args...))
|
||||
if len(fields) > 0 {
|
||||
buf = appendTab(buf)
|
||||
buf = appendFields(buf, fields)
|
||||
}
|
||||
buf = appendLF(buf)
|
||||
fmt.Fprintf(level.Writer, color.New(level.Color).Sprint(string(buf)))
|
||||
if level == LevelFatal {
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
func appendFields(dst []byte, fields map[string]interface{}) []byte {
|
||||
keys := make([]string, 0, len(fields))
|
||||
for key := range fields {
|
||||
keys = append(keys, key)
|
||||
}
|
||||
sort.Strings(keys)
|
||||
for _, key := range keys {
|
||||
dst = appendField(dst, key, fields[key])
|
||||
dst = appendTab(dst)
|
||||
}
|
||||
return dst
|
||||
}
|
||||
|
||||
func appendTab(dst []byte) []byte {
|
||||
return append(dst, ' ')
|
||||
}
|
||||
|
||||
func appendField(dst []byte, key string, val interface{}) []byte {
|
||||
dst = appendString(dst, fmt.Sprintf("%s=%v", key, val))
|
||||
return dst
|
||||
}
|
||||
|
||||
func appendString(dst []byte, s string) []byte {
|
||||
dst = append(dst, []byte(s)...)
|
||||
return dst
|
||||
}
|
||||
|
||||
func appendLF(dst []byte) []byte {
|
||||
return append(dst, '\n')
|
||||
}
|
||||
123
pkg/util/progressbar/progressbar.go
Normal file
123
pkg/util/progressbar/progressbar.go
Normal file
|
|
@ -0,0 +1,123 @@
|
|||
// Copyright 2021 storyicon@foxmail.com
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package progressbar
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/fatih/color"
|
||||
"github.com/vbauerster/mpb/v7"
|
||||
"github.com/vbauerster/mpb/v7/decor"
|
||||
)
|
||||
|
||||
// ProgressBar implements a customizable progress bar
|
||||
type ProgressBar interface {
|
||||
// Incr is used to increase progress
|
||||
Incr()
|
||||
// Wait is used to wait for the rendering of the progress bar to complete
|
||||
Wait()
|
||||
// SetPrefix is used to set the prefix of progress bar
|
||||
SetPrefix(format string, args ...interface{})
|
||||
// SetSuffix is used to set the suffix of progress bar
|
||||
SetSuffix(format string, args ...interface{})
|
||||
}
|
||||
|
||||
type progressBar struct {
|
||||
container *mpb.Progress
|
||||
bar *mpb.Bar
|
||||
prefix string
|
||||
suffix string
|
||||
}
|
||||
|
||||
// SetPrefix is used to set the prefix of progress bar
|
||||
func (s *progressBar) SetPrefix(format string, args ...interface{}) {
|
||||
s.prefix = fmt.Sprintf(format, args...)
|
||||
}
|
||||
|
||||
// SetSuffix is used to set the suffix of progress bar
|
||||
func (s *progressBar) SetSuffix(format string, args ...interface{}) {
|
||||
s.suffix = fmt.Sprintf(format, args...)
|
||||
}
|
||||
|
||||
func newEmbedProgressBar(container *mpb.Progress, bar *mpb.Bar) *progressBar {
|
||||
return &progressBar{
|
||||
container: container,
|
||||
bar: bar,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *progressBar) Incr() {
|
||||
s.bar.Increment()
|
||||
}
|
||||
|
||||
func (s *progressBar) Wait() {
|
||||
s.container.Wait()
|
||||
}
|
||||
|
||||
func getSpinner() []string {
|
||||
activeState := "[ " + color.GreenString("●") + " ] "
|
||||
defaultState := "[ ] "
|
||||
return []string{
|
||||
activeState,
|
||||
activeState,
|
||||
activeState,
|
||||
defaultState,
|
||||
defaultState,
|
||||
defaultState,
|
||||
}
|
||||
}
|
||||
|
||||
// GetProgressBar is used to get progress bar
|
||||
func GetProgressBar(count int) ProgressBar {
|
||||
var progressBar *progressBar
|
||||
container := mpb.New()
|
||||
bar := container.Add(int64(count),
|
||||
mpb.NewBarFiller(mpb.BarStyle().Lbound("[").
|
||||
Filler(color.GreenString("=")).
|
||||
Tip(color.GreenString(">")).Padding(" ").Rbound("]")),
|
||||
mpb.PrependDecorators(
|
||||
func() decor.Decorator {
|
||||
frames := getSpinner()
|
||||
var count uint
|
||||
return decor.Any(func(statistics decor.Statistics) string {
|
||||
if statistics.Completed {
|
||||
return frames[0]
|
||||
}
|
||||
frame := frames[count%uint(len(frames))]
|
||||
count++
|
||||
return frame
|
||||
})
|
||||
}(),
|
||||
decor.Any(func(statistics decor.Statistics) string {
|
||||
if progressBar != nil {
|
||||
return progressBar.prefix
|
||||
}
|
||||
return ""
|
||||
}),
|
||||
),
|
||||
mpb.AppendDecorators(
|
||||
decor.NewPercentage("%d "),
|
||||
decor.Any(func(statistics decor.Statistics) string {
|
||||
if progressBar != nil {
|
||||
return fmt.Sprintf("(%d/%d) %s", statistics.Current, count, progressBar.suffix)
|
||||
}
|
||||
return ""
|
||||
}),
|
||||
),
|
||||
mpb.BarWidth(15),
|
||||
)
|
||||
progressBar = newEmbedProgressBar(container, bar)
|
||||
return progressBar
|
||||
}
|
||||
106
pkg/util/util.go
Normal file
106
pkg/util/util.go
Normal file
|
|
@ -0,0 +1,106 @@
|
|||
// Copyright 2021 storyicon@foxmail.com
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package util
|
||||
|
||||
import (
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"runtime"
|
||||
"strings"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
// ContainsEmpty is used to check whether items contains empty string
|
||||
func ContainsEmpty(items ...string) bool {
|
||||
for _, item := range items {
|
||||
if item == "" {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// SetToSlice is used to convert set<string> to slice<string>
|
||||
func SetToSlice(set map[string]struct{}) []string {
|
||||
data := make([]string, 0, len(set))
|
||||
for key := range set {
|
||||
data = append(data, key)
|
||||
}
|
||||
return data
|
||||
}
|
||||
|
||||
// GetMapKeys is used to get the keys of map
|
||||
func GetMapKeys(dict map[string]string) []string {
|
||||
data := make([]string, 0, len(dict))
|
||||
for key := range dict {
|
||||
data = append(data, key)
|
||||
}
|
||||
return data
|
||||
}
|
||||
|
||||
// GetExitCode is used to parse exit code from cmd error
|
||||
func GetExitCode(err error) int {
|
||||
if exitErr, ok := err.(*exec.ExitError); ok {
|
||||
// The program has exited with an exit code != 0
|
||||
// This works on both Unix and Windows. Although package
|
||||
// syscall is generally platform dependent, WaitStatus is
|
||||
// defined for both Unix and Windows and in both cases has
|
||||
// an ExitStatus() method with the same signature.
|
||||
if status, ok := exitErr.Sys().(syscall.WaitStatus); ok {
|
||||
return status.ExitStatus()
|
||||
}
|
||||
}
|
||||
return 1
|
||||
}
|
||||
|
||||
var regexpEnvironmentVar = regexp.MustCompile(`\$[A-Za-z_]+`)
|
||||
|
||||
// RenderPathWithEnv is used to render path with environment
|
||||
func RenderPathWithEnv(path string) string {
|
||||
matches := regexpEnvironmentVar.FindAllString(path, -1)
|
||||
for _, match := range matches {
|
||||
path = strings.ReplaceAll(path, match, os.Getenv(match[1:]))
|
||||
}
|
||||
return filepath.Clean(path)
|
||||
}
|
||||
|
||||
// SplitGoPackageVersion is used to split go package version
|
||||
func SplitGoPackageVersion(pkg string) (path string, version string, ok bool) {
|
||||
i := strings.Index(pkg, "@")
|
||||
if i == -1 {
|
||||
return "", "", false
|
||||
}
|
||||
return pkg[:i], pkg[i+1:], true
|
||||
}
|
||||
|
||||
// JoinGoPackageVersion is used to join go path and versions
|
||||
func JoinGoPackageVersion(path, version string) string {
|
||||
return strings.Join([]string{
|
||||
path, version,
|
||||
}, "@")
|
||||
}
|
||||
|
||||
// GetBinaryFileName is used to get os based binary file name
|
||||
func GetBinaryFileName(name string) string {
|
||||
if runtime.GOOS == "windows" {
|
||||
if !strings.HasSuffix(name, ".exe") {
|
||||
return name + ".exe"
|
||||
}
|
||||
return name
|
||||
}
|
||||
return name
|
||||
}
|
||||
74
pkg/util/yaml.go
Normal file
74
pkg/util/yaml.go
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
// Copyright 2021 storyicon@foxmail.com
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package util
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
|
||||
"github.com/hashicorp/go-multierror"
|
||||
"gopkg.in/yaml.v2"
|
||||
)
|
||||
|
||||
// SplitYAML is used to split yaml
|
||||
func SplitYAML(data []byte) ([][]byte, error) {
|
||||
decoder := yaml.NewDecoder(bytes.NewReader(data))
|
||||
var parts [][]byte
|
||||
for {
|
||||
var value interface{}
|
||||
err := decoder.Decode(&value)
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
part, err := yaml.Marshal(value)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
parts = append(parts, part)
|
||||
}
|
||||
return parts, nil
|
||||
}
|
||||
|
||||
// DumpYaml is used to dump yaml into stdout
|
||||
func DumpYaml(cfg interface{}) {
|
||||
out, err := yaml.Marshal(cfg)
|
||||
if err != nil {
|
||||
fmt.Fprintln(os.Stderr, err)
|
||||
} else {
|
||||
fmt.Printf("%s\n", out)
|
||||
}
|
||||
}
|
||||
|
||||
// LoadConfig read YAML-formatted config from filename into cfg.
|
||||
func LoadConfig(filename string, pointer interface{}) error {
|
||||
buf, err := ioutil.ReadFile(filename)
|
||||
if err != nil {
|
||||
return multierror.Prefix(err, "Error reading config file")
|
||||
}
|
||||
|
||||
err = yaml.UnmarshalStrict(buf, pointer)
|
||||
if err != nil {
|
||||
return multierror.Prefix(err, "Error parsing config file")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue