diff --git a/.github/workflows/e2e-linux.yml b/.github/workflows/e2e-linux.yml new file mode 100644 index 0000000..2fd0e7f --- /dev/null +++ b/.github/workflows/e2e-linux.yml @@ -0,0 +1,32 @@ +name: linux/macos e2e test +on: + # Trigger the workflow on push or pull request, + # but only for the master branch + push: + paths-ignore: + - '**.md' + - '**.png' + pull_request: + paths-ignore: + - '**.md' + - '**.png' +jobs: + job_1: + name: Build goc binary + strategy: + matrix: + os: [ubuntu-latest, macos-latest] + runs-on: ${{ matrix.os }} + steps: + - name: Install Go + uses: actions/setup-go@v2 + with: + go-version: 1.16.x + - name: Checkout code + uses: actions/checkout@v2 + - name: Go build + run: | + go build . + - name: Use goc to build self + run: | + ./goc build -o ./gocc . \ No newline at end of file diff --git a/.github/workflows/e2e-wins.yml b/.github/workflows/e2e-wins.yml new file mode 100644 index 0000000..da3d87e --- /dev/null +++ b/.github/workflows/e2e-wins.yml @@ -0,0 +1,32 @@ +name: windows e2e test +on: + # Trigger the workflow on push or pull request, + # but only for the master branch + push: + paths-ignore: + - '**.md' + - '**.png' + pull_request: + paths-ignore: + - '**.md' + - '**.png' +jobs: + job_1: + name: Build goc binary + strategy: + matrix: + os: [windows-latest] + runs-on: ${{ matrix.os }} + steps: + - name: Install Go + uses: actions/setup-go@v2 + with: + go-version: 1.16.x + - name: Checkout code + uses: actions/checkout@v2 + - name: Go build + run: | + go build . + - name: Use goc to build self + run: | + .\goc.exe build -o gocc . \ No newline at end of file diff --git a/.github/workflows/e2e_test_check.yml b/.github/workflows/e2e_test_check.yml deleted file mode 100644 index 9b2f9b1..0000000 --- a/.github/workflows/e2e_test_check.yml +++ /dev/null @@ -1,73 +0,0 @@ -name: e2e test -on: - # Trigger the workflow on push or pull request, - # but only for the master branch - push: - paths-ignore: - - '**.md' - - '**.png' - pull_request: - paths-ignore: - - '**.md' - - '**.png' -jobs: - job_1: - name: Build goc binary - runs-on: ubuntu-latest - steps: - - name: Install Go - uses: actions/setup-go@v2 - with: - go-version: 1.14.x - - name: Checkout code - uses: actions/checkout@v2 - - name: Go build - run: | - go build - - name: Use goc to build self - run: | - ./goc build --output ./gocc --debug - - name: Upload goc binary - uses: actions/upload-artifact@v2 - with: - name: goc - path: goc - - name: Upload covered self goc binary - uses: actions/upload-artifact@v2 - with: - name: gocc - path: gocc - - job_2: - name: E2E test - needs: job_1 - strategy: - matrix: - go-version: [1.11.x, 1.12.x, 1.13.x, 1.14.x, 1.15.x, 1.16.x] - runs-on: ubuntu-latest - steps: - - name: Install Go - uses: actions/setup-go@v2 - with: - go-version: ${{ matrix.go-version }} - - name: Checkout code - uses: actions/checkout@v2 - - name: Download built binary - uses: actions/download-artifact@v2 - with: - path: /home/runner/tools - - name: Install bats-core - run: | - git clone https://github.com/bats-core/bats-core.git - cd bats-core - sudo ./install.sh /usr/local - - name: Do test - env: - GOVERSION: ${{ matrix.go-version }} - run: | - chmod +x /home/runner/tools/goc/goc - export PATH=/home/runner/tools/goc:$PATH - chmod +x /home/runner/tools/gocc/gocc - export PATH=/home/runner/tools/gocc:$PATH - cd tests - ./run-ci-actions.sh \ No newline at end of file diff --git a/.github/workflows/golangci-lint.yml b/.github/workflows/golangci-lint.yml deleted file mode 100644 index ec58f5c..0000000 --- a/.github/workflows/golangci-lint.yml +++ /dev/null @@ -1,23 +0,0 @@ -name: golangci-lint -on: - pull_request: -jobs: - golangci: - name: lint - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - name: golangci-lint - uses: golangci/golangci-lint-action@v2 - with: - # Required: the version of golangci-lint is required and must be specified without patch version: we always use the latest patch version. - version: v1.29 - - # Optional: working directory, useful for monorepos - # working-directory: somedir - - # Optional: golangci-lint command line arguments. - # args: --issues-exit-code=0 - - # Optional: show only new issues if it's a pull request. The default value is `false`. - only-new-issues: true \ No newline at end of file diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml deleted file mode 100644 index eb559a7..0000000 --- a/.github/workflows/release.yml +++ /dev/null @@ -1,55 +0,0 @@ -on: - release: - types: [published,edited] -name: Build Release -jobs: - release-linux-amd64: - name: release linux/amd64 - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@master - - name: Install Go - uses: actions/setup-go@v2 - with: - go-version: 1.14.x - - name: compile and release - run: | - ./ci-build.sh - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - GOARCH: amd64 - GOOS: linux - - release-linux-386: - name: release linux/386 - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@master - - name: Install Go - uses: actions/setup-go@v2 - with: - go-version: 1.14.x - - name: compile and release - run: | - ./ci-build.sh - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - GOARCH: "386" - GOOS: linux - - release-darwin-amd64: - name: release darwin/amd64 - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@master - - name: Install Go - uses: actions/setup-go@v2 - with: - go-version: 1.14.x - - name: compile and release - run: | - ./ci-build.sh - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - GOARCH: amd64 - GOOS: darwin \ No newline at end of file diff --git a/.github/workflows/style_check.yml b/.github/workflows/style_check.yml index e96c9fa..f04af15 100644 --- a/.github/workflows/style_check.yml +++ b/.github/workflows/style_check.yml @@ -15,7 +15,7 @@ jobs: name: vet and gofmt strategy: matrix: - go-version: [1.13.x, 1.14.x, 1.15.x] + go-version: [1.16.x] runs-on: ubuntu-latest steps: - name: Install Go @@ -36,4 +36,4 @@ jobs: echo "${diff}" echo "Please run this command to fix: [find . -name "*.go" | xargs gofmt -s -w]" exit 1 - fi + fi \ No newline at end of file diff --git a/.github/workflows/ut_check.yml b/.github/workflows/ut-check.yml similarity index 93% rename from .github/workflows/ut_check.yml rename to .github/workflows/ut-check.yml index 533fd29..d2a37d5 100644 --- a/.github/workflows/ut_check.yml +++ b/.github/workflows/ut-check.yml @@ -15,7 +15,7 @@ jobs: name: go test strategy: matrix: - go-version: [1.13.x, 1.14.x, 1.15.x, 1.16.x] + go-version: [1.16.x] runs-on: ubuntu-latest steps: - name: Install Go @@ -31,4 +31,4 @@ jobs: run: | export DEFAULT_EXCEPT_PKGS=e2e go test -p 1 -coverprofile=coverage.txt $(go list ./... | grep -v -E $DEFAULT_EXCEPT_PKGS) - bash <(curl -s https://codecov.io/bash) -F unittest-$GOVERSION + bash <(curl -s https://codecov.io/bash) -F unittest-$GOVERSION \ No newline at end of file diff --git a/.gitignore b/.gitignore index e3dd50f..e69de29 100644 --- a/.gitignore +++ b/.gitignore @@ -1,13 +0,0 @@ -# ignore log file -**/goc.log - -# binary -goc - -# the temp file to save service address -_svrs_address.txt - -# other -*.iml -.DS_Store -.idea diff --git a/Makefile b/Makefile deleted file mode 100644 index 88ffe4b..0000000 --- a/Makefile +++ /dev/null @@ -1,21 +0,0 @@ -DEFAULT_EXCEPT_PKGS := e2e - -all: - go install ./... - -test: - go test -cover -p 1 `go list ./... | grep -v -E ${DEFAULT_EXCEPT_PKGS}` - -fmt: - go fmt ./... - -govet-check: - go vet ./... - -clean: - find tests/ -type f -name '*.bak' -delete - find tests/ -type f -name '*.cov' -delete - find tests/ -type f -name 'simple-project' -delete - find tests/ -type f -name '*_profile_listen_addr' -delete - find tests/ -type f -name 'simple_gopath_project' -delete - \ No newline at end of file diff --git a/README.md b/README.md index 97e5ff1..ecec669 100644 --- a/README.md +++ b/README.md @@ -1,88 +1,73 @@ # goc -[![Go Report Card](https://goreportcard.com/badge/github.com/qiniu/goc)](https://goreportcard.com/report/github.com/qiniu/goc) -![](https://github.com/qiniu/goc/workflows/ut-check/badge.svg) -![](https://github.com/qiniu/goc/workflows/style-check/badge.svg) -![](https://github.com/qiniu/goc/workflows/e2e%20test/badge.svg) -![Build Release](https://github.com/qiniu/goc/workflows/Build%20Release/badge.svg) -[![codecov](https://codecov.io/gh/qiniu/goc/branch/master/graph/badge.svg)](https://codecov.io/gh/qiniu/goc) -[![GoDoc](https://godoc.org/github.com/qiniu/goc?status.svg)](https://godoc.org/github.com/qiniu/goc) -[中文页](README_zh.md) | +goc v2 版本开发中 -goc is a comprehensive coverage testing system for The Go Programming Language, especially for some complex scenarios, like system testing code coverage collection and -accurate testing. +## Quick Start -Enjoy, Have Fun! -![Demo](docs/images/intro.gif) +### 编译要求 -## Installation +`Go 1.16+` -Download the latest version from [Github Releases](https://github.com/qiniu/goc/releases) page. +### 新特性一览 -Goc supports both `GOPATH` project and `Go Modules` project with **Go 1.11+**. However, for developing goc, you need to install **Go 1.13+**. +#### 1. 只支持 go module 工程 -## Examples -You can use goc tool in many scenarios. +考虑到 GOPATH 已被官方明确将淘汰,以及支持 GOPATH 工程带来的巨大工作量,v2 不再支持 GOPATH 工程。 -### Code Coverage Collection for Your Golang System Tests -Goc can collect code coverages at runtime for your long-run golang applications. To do that, normally just need three steps: +#### 2. 命令行 flag 解析优化 -1. use `goc server` to start a service registry center: - ``` - ➜ simple-go-server git:(master) ✗ goc server - ``` -2. use `goc build` to build the target service, and run the generated binary. Here let's take the [simple-go-server](https://github.com/CarlJi/simple-go-server) project as example: - ``` - ➜ simple-go-server git:(master) ✗ goc build . - ... // omit logs - ➜ simple-go-server git:(master) ✗ ./simple-go-server - ``` -3. use `goc profile` to get the code coverage profile of the started simple server above: - ``` - ➜ simple-go-server git:(master) ✗ goc profile - mode: atomic - enricofoltran/simple-go-server/main.go:30.13,48.33 13 1 - enricofoltran/simple-go-server/main.go:48.33,50.3 1 0 - enricofoltran/simple-go-server/main.go:52.2,65.12 5 1 - enricofoltran/simple-go-server/main.go:65.12,74.46 7 1 - enricofoltran/simple-go-server/main.go:74.46,76.4 1 0 - ... - ``` +在 v1 版本中,`go build -o -ldflags 'foo=bar' ./app/main.go` 与 goc 命令并不等价,首先你需要切换到 `.app/` 目录中,然后执行 `goc build --buildflags="-o -ldflags 'foo=bar' ."`。这个转换给使用者带来不小的负担,特别是 `'"` 混杂在一起时,感觉会更难受。 -### Show Code Coverage Change at Runtime in Vscode +在 v2 版本中,goc 编译命令和 go 编译命令已经极为相似,例如 -We provide a vscode extension - [Goc Coverage](https://marketplace.visualstudio.com/items?itemName=lyyyuna.goc) which can show highlighted covered source code at runtime. +```bash +go build -o -ldflags 'foo=bar' ./app/main.go +# 等价于 +goc build -o -ldflags 'foo=bar' ./app/main.go +# +go build -o -ldflags 'foo=bar' ./app +# 等价于 +goc build -o -ldflags 'foo=bar' ./app +# +go install ./app/... +# 等价于 +goc install ./app/... +# +``` -![Extension](docs/images/goc-vscode.gif) +由于 go 命令对 flags 和 args 的相对位置有着严格要求:`go build [-o output] [build flags] [packages]`,所以在指定 goc 自己的 flags (所有 goc flags 都是 `--` 开头)必须和 `build flags` 位置保持相同,即: -## Tips +```bash +goc build --debug -o /home/app . # 合法 -1. To understand the execution details of goc tool, you can use the `--debug` flag. Also we appreciate if you can provide such logs when submitting a bug to us. +goc build -o /home/app . --debug # 非法 +``` -2. By default, the covered service will listen a random port in order to communicate with the goc server. This may not be suitable in [docker](https://docs.docker.com/engine/reference/commandline/run/#publish-or-expose-port--p---expose) or [kubernetes](https://kubernetes.io/docs/concepts/services-networking/service/#defining-a-service) environment since the port must be exposed explicitly in order to be accessible by others in such environment. For this kind of scenario, you can use `--agentport` flag to specify a fixed port when calling `goc build` or `goc install`. +#### 3. 日志优化 -3. To use a remote goc server, you can use `--center` flag to compile the target service with `goc build` or `goc install` command. +带颜色日志,以及长时间操作时(例如 build, copy)会有转圈动画。 -4. The coverage data is stored on each covered service side, so if one service needs to restart during test, this service's coverage data will be lost. For this case, you can use following steps to handle: +#### 4. 被测服务部署优化 - 1. Before the service restarts, collect coverage with `goc profile -o a.cov` - 2. After service restarted and test finished, collect coverage again with `goc profile -o b.cov` - 3. Merge two coverage profiles together: `goc merge a.cov b.cov -o merge.cov` +在 v1 版本中,当被测服务在 docker 中,goc server 在外部时,会要求在容器启动时额外开启端口转发,并且编译还需带额外参数。这给部署带来不便。 -## RoadMap -- [x] Support code coverage collection for system testing. -- [x] Support code coverage counters clear for the services under test at runtime. -- [x] Support develop mode towards accurate testing. -- [x] Support code coverage diff based on Pull Request. -- [ ] Optimize the performance costed by code coverage counters. +在 v2 版本中,不再有这一限制,只需要 goc server 能够被被测服务访问即可。 -## Contributing -We welcome all kinds of contribution, including bug reports, feature requests, documentation improvements, UI refinements, etc. +#### 5. watch 模式 -Thanks to all [contributors](https://github.com/qiniu/goc/graphs/contributors)!! +当使用 `goc build --mode watch .` 编译后,被测服务任何覆盖率变化都将实时推送到 goc server。 -## License -Goc is released under the Apache 2.0 license. See [LICENSE.txt](https://github.com/qiniu/goc/blob/master/LICENSE) +用户可以使用该 websocket 连接 `ws://[goc_server_host]/cover/ws/watch` 观察到被测服务的新触发代码块,推送信息格式如下: -## Join goc WeChat Group -![WeChat](docs/images/wechat.png) \ No newline at end of file +```bash +qiniu.com/kodo/apiserver/server/main.go:42.49,43.13 1 0 +# +# importpath/filename.go:Line0.Col1,Line1,Col1 1 0 +``` + +除此之外,原来的全局整体覆盖率可正常获取,不受影响。 + +#### 6. 跨平台支持 + +1. 支持 `Linux/Macos/Windows` +2. 支持 go 的交叉编译 \ No newline at end of file diff --git a/README_zh.md b/README_zh.md deleted file mode 100644 index c866e47..0000000 --- a/README_zh.md +++ /dev/null @@ -1,97 +0,0 @@ -# goc - -[![Go Report Card](https://goreportcard.com/badge/github.com/qiniu/goc)](https://goreportcard.com/report/github.com/qiniu/goc) -![](https://github.com/qiniu/goc/workflows/ut-check/badge.svg) -![](https://github.com/qiniu/goc/workflows/style-check/badge.svg) -![](https://github.com/qiniu/goc/workflows/e2e%20test/badge.svg) -![Build Release](https://github.com/qiniu/goc/workflows/Build%20Release/badge.svg) -[![codecov](https://codecov.io/gh/qiniu/goc/branch/master/graph/badge.svg)](https://codecov.io/gh/qiniu/goc) -[![GoDoc](https://godoc.org/github.com/qiniu/goc?status.svg)](https://godoc.org/github.com/qiniu/goc) - -goc 是专为 Go 语言打造的一个综合覆盖率收集系统,尤其适合复杂的测试场景,比如系统测试时的代码覆盖率收集以及精准测试。 - -希望你们喜欢~ - -![Demo](docs/images/intro.gif) - -## 安装 - -最新版本在该页面下载 [Github Releases](https://github.com/qiniu/goc/releases)。 - -goc 同时支持 `GOPATH` 工程和 `Go Modules` 工程,且 Go 版本要求 **Go 1.11+**。如果想参与 goc 的开发,你必须使用 **Go 1.13+**。 - -## 例子 - -goc 有多种使用场景。 - -### 在系统测试中收集代码覆盖率 - -goc 可以实时收集长时运行的 golang 服务覆盖率。收集步骤只需要下面三步: - -1. 运行 `goc server` 命令启动一个服务注册中心: - ``` - ➜ simple-go-server git:(master) ✗ goc server - ``` -2. 运行 `goc build` 命令编译目标服务,然后启动插过桩的二进制。下面以 [simple-go-server](https://github.com/CarlJi/simple-go-server) 工程为例: - ``` - ➜ simple-go-server git:(master) ✗ goc build . - ... // omit logs - ➜ simple-go-server git:(master) ✗ ./simple-go-server - ``` -3. 运行 `goc profile` 命令收集刚启动的 simple server 的代码覆盖率: - ``` - ➜ simple-go-server git:(master) ✗ goc profile - mode: atomic - enricofoltran/simple-go-server/main.go:30.13,48.33 13 1 - enricofoltran/simple-go-server/main.go:48.33,50.3 1 0 - enricofoltran/simple-go-server/main.go:52.2,65.12 5 1 - enricofoltran/simple-go-server/main.go:65.12,74.46 7 1 - enricofoltran/simple-go-server/main.go:74.46,76.4 1 0 - ... - ``` - -### Vscode 中实时展示覆盖率动态变化 - -我们提供了一个 vscode 插件 - [Goc Coverage](https://marketplace.visualstudio.com/items?itemName=lyyyuna.goc)。该插件可以在运行时高亮覆盖过的代码。 - -![Extension](docs/images/goc-vscode.gif) - -## Tips - -1. goc 命令加上 `--debug` 会打印详细的日志。我们建议在提交 bug 时附上详细日志。 - -2. 默认情况下,插桩过的服务会监听在一个随机的端口,注册中心会通过这个端口与服务通信。然而,对于 [docker](https://docs.docker.com/engine/reference/commandline/run/#publish-or-expose-port--p---expose) 和 [kubernetes](https://kubernetes.io/docs/concepts/services-networking/service/#defining-a-service) 容器化运行环境,对外暴露端口需在容器启动前指定。针对这种场景,你可以在 `goc build` 或 `goc install` 时使用 `--agentport` 来指定插桩过的服务监听在固定的端口。 - -3. 如果注册中心不在本机,你可以在 `goc build` 或 `goc install` 编译目标服务时使用 `--center` 指定远端注册中心地址。 - -4. 目前覆盖率数据存储在插过桩的服务测,如果某个服务中途需要重启,那么其覆盖率数据在重启后会丢失。针对这个场景,你可以通过以下步骤解决: - - 1. 在重启前,通过 `goc profile -o a.cov` 命令收集一次覆盖率 - 2. 测试结束后,通过 `goc profile -o b.cov` 命令再收集一次覆盖率 - 3. 通过 `goc merge a.cov b.cov -o merge.cov` 命令合并两次的覆盖率 - -## Blogs - -- [Go语言系统测试覆盖率收集利器 goc](https://mp.weixin.qq.com/s/DzXEXwepaouSuD2dPVloOg) -- [聊聊Go代码覆盖率技术与最佳实践](https://mp.weixin.qq.com/s/SQHzsfV5T_B8fmt9NzGA7Q) - -## RoadMap - -- [x] 支持系统测试中收集代码覆盖率 -- [x] 支持运行时对被测服务代码覆盖率计数器清零 -- [x] 支持精准测试 -- [x] 支持基于 Pull Request 的增量代码覆盖率报告 -- [ ] 优化插桩计数器带来的性能损耗 - -## Contributing - -我们欢迎各种形式的贡献,包括提交 bug、提新需求、优化文档和改进 UI 等等。 - -感谢所有的[贡献者](https://github.com/qiniu/goc/graphs/contributors)!! - -## License - -Goc is released under the Apache 2.0 license. See [LICENSE.txt](https://github.com/qiniu/goc/blob/master/LICENSE) - -## 加入微信群聊 -![WeChat](docs/images/wechat.png) \ No newline at end of file diff --git a/ci-build.sh b/ci-build.sh deleted file mode 100755 index d888a5d..0000000 --- a/ci-build.sh +++ /dev/null @@ -1,33 +0,0 @@ -#!/bin/bash - -set -eux - -EVENT_DATA=$(cat $GITHUB_EVENT_PATH) -echo $EVENT_DATA | jq . -UPLOAD_URL=$(echo $EVENT_DATA | jq -r .release.upload_url) -UPLOAD_URL=${UPLOAD_URL/\{?name,label\}/} -RELEASE_VERSION=$(echo $EVENT_DATA | jq -r .release.tag_name) -PROJECT_NAME=$(basename $GITHUB_REPOSITORY) -NAME="${NAME:-${PROJECT_NAME}-${RELEASE_VERSION}}-${GOOS}-${GOARCH}" - -CGO_ENABLED=0 go build -ldflags "-X 'github.com/qiniu/goc/cmd.version=${RELEASE_VERSION}'" . - -ARCHIVE=tmp.tar.gz -FILE_LIST=goc -tar cvfz $ARCHIVE ${FILE_LIST} - -CHECKSUM=$(md5sum ${ARCHIVE} | cut -d ' ' -f 1) - -curl \ - -X POST \ - --data-binary @${ARCHIVE} \ - -H 'Content-Type: application/octet-stream' \ - -H "Authorization: Bearer ${GITHUB_TOKEN}" \ - "${UPLOAD_URL}?name=${NAME}.${ARCHIVE/tmp./}" - -curl \ - -X POST \ - --data $CHECKSUM \ - -H 'Content-Type: text/plain' \ - -H "Authorization: Bearer ${GITHUB_TOKEN}" \ - "${UPLOAD_URL}?name=${NAME}_md5.txt" \ No newline at end of file diff --git a/cmd/build.go b/cmd/build.go index eb4a54b..1aab87c 100644 --- a/cmd/build.go +++ b/cmd/build.go @@ -1,96 +1,25 @@ -/* - Copyright 2020 Qiniu Cloud (qiniu.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 cmd import ( - "os" - - log "github.com/sirupsen/logrus" - - "github.com/qiniu/goc/pkg/build" - "github.com/qiniu/goc/pkg/cover" + "github.com/qiniu/goc/v2/pkg/build" + "github.com/qiniu/goc/v2/pkg/config" "github.com/spf13/cobra" ) var buildCmd = &cobra.Command{ - Use: "build", - Short: "Do cover for all go files and execute go build command", - Long: ` -Build command will copy the project code and its necessary dependencies to a temporary directory, then do cover for the target, binaries will be generated to their original place. -`, - Example: ` -# Build the current binary with cover variables injected. The binary will be generated in the current folder. -goc build . + Use: "build", + Run: buildAction, -# Build the current binary with cover variables injected, and set the registry center to http://127.0.0.1:7777. -goc build --center=http://127.0.0.1:7777 - -# Build the current binary with cover variables injected, and redirect output to /to/this/path. -goc build --output /to/this/path - -# Build the current binary with cover variables injected, and set necessary build flags: -ldflags "-extldflags -static" -tags="embed kodo". -goc build --buildflags="-ldflags '-extldflags -static' -tags='embed kodo'" -`, - Run: func(cmd *cobra.Command, args []string) { - wd, err := os.Getwd() - if err != nil { - log.Fatalf("Fail to build: %v", err) - } - runBuild(args, wd) - }, + DisableFlagParsing: true, // build 命令需要用原生 go 的方式处理 flags } -var buildOutput string - func init() { - addBuildFlags(buildCmd.Flags()) - buildCmd.Flags().StringVarP(&buildOutput, "output", "o", "", "it forces build to write the resulting executable to the named output file") + buildCmd.Flags().StringVarP(&config.GocConfig.Mode, "mode", "", "count", "coverage mode: set, count, atomic, watch") + buildCmd.Flags().StringVarP(&config.GocConfig.Host, "host", "", "127.0.0.1:7777", "specify the host of the goc sever") rootCmd.AddCommand(buildCmd) } -func runBuild(args []string, wd string) { - gocBuild, err := build.NewBuild(buildFlags, args, wd, buildOutput) - if err != nil { - log.Fatalf("Fail to build: %v", err) - } - // remove temporary directory if needed - defer gocBuild.Clean() - // doCover with original buildFlags, with new GOPATH( tmp:original ) - // in the tmp directory - ci := &cover.CoverInfo{ - Args: buildFlags, - GoPath: gocBuild.NewGOPATH, - Target: gocBuild.TmpDir, - Mode: coverMode.String(), - AgentPort: agentPort.String(), - Center: center, - IsMod: gocBuild.IsMod, - ModRootPath: gocBuild.ModRootPath, - OneMainPackage: true, // it is a go build - GlobalCoverVarImportPath: gocBuild.GlobalCoverVarImportPath, - } - err = cover.Execute(ci) - if err != nil { - log.Fatalf("Fail to build: %v", err) - } - // do install in the temporary directory - err = gocBuild.Build() - if err != nil { - log.Fatalf("Fail to build: %v", err) - } - return +func buildAction(cmd *cobra.Command, args []string) { + b := build.NewBuild(cmd, args) + b.Build() } diff --git a/cmd/build_test.go b/cmd/build_test.go deleted file mode 100644 index f3677b3..0000000 --- a/cmd/build_test.go +++ /dev/null @@ -1,110 +0,0 @@ -/* - Copyright 2020 Qiniu Cloud (qiniu.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 cmd - -import ( - "os" - "os/exec" - "path/filepath" - "strings" - "testing" - "time" - - "github.com/stretchr/testify/assert" -) - -var baseDir string - -func init() { - baseDir, _ = os.Getwd() -} - -func TestGeneratedBinary(t *testing.T) { - startTime := time.Now() - - workingDir := filepath.Join(baseDir, "../tests/samples/simple_project") - gopath := "" - - os.Setenv("GOPATH", gopath) - os.Setenv("GO111MODULE", "on") - - buildFlags, buildOutput = "", "" - args := []string{"."} - runBuild(args, workingDir) - - obj := filepath.Join(workingDir, "simple-project") - fInfo, err := os.Lstat(obj) - assert.Equal(t, err, nil, "the binary should be generated.") - assert.Equal(t, startTime.Before(fInfo.ModTime()), true, obj+"new binary should be generated, not the old one") - - cmd := exec.Command("go", "tool", "objdump", "simple-project") - cmd.Dir = workingDir - out, _ := cmd.CombinedOutput() - cnt := strings.Count(string(out), "main.registerSelf") - assert.Equal(t, cnt > 0, true, "main.registerSelf function should be in the binary") - - cnt = strings.Count(string(out), "GoCover") - assert.Equal(t, cnt > 0, true, "GoCover variable should be in the binary") -} - -func TestBuildBinaryName(t *testing.T) { - startTime := time.Now() - - workingDir := filepath.Join(baseDir, "../tests/samples/simple_project2") - gopath := "" - - os.Setenv("GOPATH", gopath) - os.Setenv("GO111MODULE", "on") - - buildFlags, buildOutput = "", "" - args := []string{"."} - runBuild(args, workingDir) - - obj := filepath.Join(workingDir, "simple-project") - fInfo, err := os.Lstat(obj) - assert.Equal(t, err, nil, "the binary should be generated.") - assert.Equal(t, startTime.Before(fInfo.ModTime()), true, obj+"new binary should be generated, not the old one") - - cmd := exec.Command("go", "tool", "objdump", "simple-project") - cmd.Dir = workingDir - out, _ := cmd.CombinedOutput() - cnt := strings.Count(string(out), "main.registerSelf") - assert.Equal(t, cnt > 0, true, "main.registerSelf function should be in the binary") - - cnt = strings.Count(string(out), "GoCover") - assert.Equal(t, cnt > 0, true, "GoCover variable should be in the binary") -} - -// test if goc can get variables in internal package -func TestBuildBinaryForInternalPackage(t *testing.T) { - startTime := time.Now() - - workingDir := filepath.Join(baseDir, "../tests/samples/simple_project_with_internal") - gopath := "" - - os.Setenv("GOPATH", gopath) - os.Setenv("GO111MODULE", "on") - - buildFlags, buildOutput = "", "" - args := []string{"."} - runBuild(args, workingDir) - - obj := filepath.Join(workingDir, "simple-project") - fInfo, err := os.Lstat(obj) - assert.Equal(t, err, nil, "the binary should be generated.") - assert.Equal(t, startTime.Before(fInfo.ModTime()), true, obj+"new binary should be generated, not the old one") -} diff --git a/cmd/clear.go b/cmd/clear.go deleted file mode 100644 index 2e5aea2..0000000 --- a/cmd/clear.go +++ /dev/null @@ -1,58 +0,0 @@ -/* - Copyright 2020 Qiniu Cloud (qiniu.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 cmd - -import ( - "fmt" - "os" - - log "github.com/sirupsen/logrus" - - "github.com/qiniu/goc/pkg/cover" - "github.com/spf13/cobra" -) - -var clearCmd = &cobra.Command{ - Use: "clear", - Short: "Clear code coverage counters of all the registered services", - Long: `Clear code coverage counters for the services under test at runtime.`, - Example: ` -# Clear coverage counter from default register center http://127.0.0.1:7777. -goc clear - -# Clear coverage counter from specified register center. -goc clear --center=http://192.168.1.1:8080 -`, - Run: func(cmd *cobra.Command, args []string) { - p := cover.ProfileParam{ - Service: svrList, - Address: addrList, - } - res, err := cover.NewWorker(center).Clear(p) - if err != nil { - log.Fatalf("call host %v failed, err: %v, response: %v", center, err, string(res)) - } - fmt.Fprint(os.Stdout, string(res)) - }, -} - -func init() { - addBasicFlags(clearCmd.Flags()) - clearCmd.Flags().StringSliceVarP(&svrList, "service", "", nil, "service name to clear profile, see 'goc list' for all services.") - clearCmd.Flags().StringSliceVarP(&addrList, "address", "", nil, "address to clear profile, see 'goc list' for all addresses.") - rootCmd.AddCommand(clearCmd) -} diff --git a/cmd/commonflags.go b/cmd/commonflags.go deleted file mode 100644 index 9440276..0000000 --- a/cmd/commonflags.go +++ /dev/null @@ -1,126 +0,0 @@ -/* - Copyright 2020 Qiniu Cloud (qiniu.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 cmd - -import ( - "fmt" - "net" - - "github.com/spf13/pflag" - "github.com/spf13/viper" -) - -var ( - target string - center string - agentPort AgentPort - debugGoc bool - debugInCISyncFile string - buildFlags string - - goRunExecFlag string - goRunArguments string -) - -var coverMode = CoverMode{ - mode: "count", -} - -// addBasicFlags adds a -func addBasicFlags(cmdset *pflag.FlagSet) { - cmdset.StringVar(¢er, "center", "http://127.0.0.1:7777", "cover profile host center") - // bind to viper - viper.BindPFlags(cmdset) -} - -func addCommonFlags(cmdset *pflag.FlagSet) { - addBasicFlags(cmdset) - cmdset.Var(&coverMode, "mode", "coverage mode: set, count, atomic") - cmdset.Var(&agentPort, "agentport", "a fixed port such as :8100 for registered service communicate with goc server. if not provided, using a random one") - cmdset.StringVar(&buildFlags, "buildflags", "", "specify the build flags") - // bind to viper - viper.BindPFlags(cmdset) -} - -func addBuildFlags(cmdset *pflag.FlagSet) { - addCommonFlags(cmdset) - // bind to viper - viper.BindPFlags(cmdset) -} - -func addRunFlags(cmdset *pflag.FlagSet) { - addBuildFlags(cmdset) - cmdset.StringVar(&goRunExecFlag, "exec", "", "same as -exec flag in 'go run' command") - cmdset.StringVar(&goRunArguments, "arguments", "", "same as 'arguments' in 'go run' command") - // bind to viper - viper.BindPFlags(cmdset) -} - -// CoverMode represents the covermode when doing cover for source code -type CoverMode struct { - mode string -} - -func (m *CoverMode) String() string { - return m.mode -} - -// Set sets the value to the CoverMode struct, use 'count' as default if v is empty -func (m *CoverMode) Set(v string) error { - if v == "" { - m.mode = "count" - return nil - } - if v != "set" && v != "count" && v != "atomic" { - return fmt.Errorf("unknown mode") - } - m.mode = v - return nil -} - -// Type returns the type of CoverMode -func (m *CoverMode) Type() string { - return "string" -} - -// AgentPort is the struct to do agentPort check -type AgentPort struct { - port string -} - -func (agent *AgentPort) String() string { - return agent.port -} - -// Set sets the value to the AgentPort struct -func (agent *AgentPort) Set(v string) error { - if v == "" { - agent.port = "" - return nil - } - _, _, err := net.SplitHostPort(v) - if err != nil { - return err - } - agent.port = v - return nil -} - -// Type returns the type of AgentPort -func (agent *AgentPort) Type() string { - return "string" -} diff --git a/cmd/commonflags_test.go b/cmd/commonflags_test.go deleted file mode 100644 index ea5f4f0..0000000 --- a/cmd/commonflags_test.go +++ /dev/null @@ -1,110 +0,0 @@ -/* - Copyright 2020 Qiniu Cloud (qiniu.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 cmd - -import ( - "errors" - "fmt" - "testing" - - "github.com/stretchr/testify/assert" -) - -func TestCoverModeFlag(t *testing.T) { - var tcs = []struct { - value string - expectedValue interface{} - err interface{} - }{ - { - value: "", - expectedValue: "count", - err: nil, - }, - { - value: "set", - expectedValue: "set", - err: nil, - }, - { - value: "count", - expectedValue: "count", - err: nil, - }, - { - value: "atomic", - expectedValue: "atomic", - err: nil, - }, - { - value: "xxxxx", - expectedValue: "", - err: errors.New("unknown mode"), - }, - { - value: "123333", - expectedValue: "", - err: errors.New("unknown mode"), - }, - } - for _, tc := range tcs { - mode := &CoverMode{} - err := mode.Set(tc.value) - actual := mode.String() - assert.Equal(t, actual, tc.expectedValue, fmt.Sprintf("check mode flag value failed, expected %s, got %s", tc.expectedValue, actual)) - assert.Equal(t, err, tc.err, fmt.Sprintf("check mode flag error, expected %s, got %s", tc.err, err)) - } -} - -func TestAgentPortFlag(t *testing.T) { - var tcs = []struct { - value string - expectedValue interface{} - isErr bool - }{ - { - value: "", - expectedValue: "", - isErr: false, - }, - { - value: ":8888", - expectedValue: ":8888", - isErr: false, - }, - { - value: "8888", - expectedValue: "", - isErr: true, - }, - { - value: "::8888", - expectedValue: "", - isErr: true, - }, - } - for _, tc := range tcs { - agent := &AgentPort{} - err := agent.Set(tc.value) - if tc.isErr { - assert.NotEqual(t, nil, err, fmt.Sprintf("check agentport flag error, expected %v, got %v", nil, err)) - } else { - actual := agent.String() - assert.Equal(t, tc.expectedValue, actual, fmt.Sprintf("check agentport flag value failed, expected %s, got %s", tc.expectedValue, actual)) - } - } -} diff --git a/cmd/cover.go b/cmd/cover.go deleted file mode 100644 index dec4e5b..0000000 --- a/cmd/cover.go +++ /dev/null @@ -1,61 +0,0 @@ -/* - Copyright 2020 Qiniu Cloud (qiniu.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 cmd - -import ( - "github.com/qiniu/goc/pkg/cover" - "github.com/spf13/cobra" - "github.com/spf13/viper" -) - -var coverCmd = &cobra.Command{ - Use: "cover", - Short: "Do cover for the target source", - Long: `Do cover for the target source. You can select different cover mode (set, count, atomic), default: count`, - Example: ` -# Do cover for the current path, default center: http://127.0.0.1:7777, default cover mode: count. -goc cover - -# Do cover for the current path, default cover mode: count. -goc cover --center=http://127.0.0.1:7777 - -# Do cover for the target path, cover mode: atomic. -goc cover --center=http://127.0.0.1:7777 --target=/path/to/target --mode=atomic -`, - Hidden: true, - Run: func(cmd *cobra.Command, args []string) { - var buildFlags string - buildFlags = viper.GetString("buildflags") - - ci := &cover.CoverInfo{ - Args: buildFlags, - GoPath: "", - Target: target, - Mode: coverMode.String(), - AgentPort: agentPort.String(), - Center: center, - OneMainPackage: false, - } - _ = cover.Execute(ci) - }, -} - -func init() { - coverCmd.Flags().StringVar(&target, "target", ".", "target folder to cover") - addCommonFlags(coverCmd.Flags()) - rootCmd.AddCommand(coverCmd) -} diff --git a/cmd/diff.go b/cmd/diff.go deleted file mode 100644 index 6ad26c9..0000000 --- a/cmd/diff.go +++ /dev/null @@ -1,209 +0,0 @@ -/* - Copyright 2020 Qiniu Cloud (qiniu.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 cmd - -import ( - "encoding/json" - "io/ioutil" - "os" - - "github.com/olekukonko/tablewriter" - "github.com/sirupsen/logrus" - "github.com/spf13/cobra" - - "github.com/qiniu/goc/pkg/cover" - "github.com/qiniu/goc/pkg/github" - "github.com/qiniu/goc/pkg/prow" - "github.com/qiniu/goc/pkg/qiniu" -) - -var diffCmd = &cobra.Command{ - Use: "diff", - Short: "Do coverage profile diff analysis, it can also work with prow and post comments to github pull request if needed", - Example: ` # Diff two local coverage profile and display - goc diff --new-profile= --base-profile= - - # Diff local coverage profile with the remote one in prow job using default qiniu-credential - goc diff --prow-postsubmit-job= --new-profile= - - # Calculate and display full diff coverage between new-profile and base-profile, not concerned github changed files - goc diff --prow-postsubmit-job= --new-profile= --full-diff=true - - # Diff local coverage profile with the remote one in prow job - goc diff --prow-postsubmit-job= --prow-remote-profile-name= - --qiniu-credential= --new-profile= - - # Diff coverage profile with the remote one in prow job, and post comments to github PR - goc diff --prow-postsubmit-job= --prow-profile= - --github-token= --github-user= --github-comment-prefix= - --qiniu-credential= --coverage-threshold-percentage= --new-profile= - `, - Run: func(cmd *cobra.Command, args []string) { - if baseProfile != "" { - doDiffForLocalProfiles(cmd, args) - } else if prowPostSubmitJob != "" { - doDiffUnderProw(cmd, args) - } else { - logrus.Fatalf("either base-profile or prow-postsubmit-job must be provided") - } - }, -} - -var ( - newProfile string - baseProfile string - coverageThreshold int - - prowPostSubmitJob string - prowProfile string - - githubToken string - githubUser string - githubCommentPrefix string - - qiniuCredential string - - robotName string - fullDiff bool -) - -func init() { - diffCmd.Flags().StringVarP(&newProfile, "new-profile", "n", "", "local profile which works as the target to analysis") - diffCmd.MarkFlagRequired("new-profile") - diffCmd.Flags().StringVarP(&baseProfile, "base-profile", "b", "", "another local profile which works as baseline to compare with the target") - diffCmd.Flags().IntVarP(&coverageThreshold, "coverage-threshold-percentage", "", 0, "coverage threshold percentage") - diffCmd.Flags().StringVarP(&prowPostSubmitJob, "prow-postsubmit-job", "", "", "prow postsubmit job which used to find the base profile") - diffCmd.Flags().StringVarP(&prowProfile, "prow-remote-profile-name", "", "filtered.cov", "the name of profile in prow postsubmit job, which used as the base profile to compare") - diffCmd.Flags().StringVarP(&githubToken, "github-token", "", "/etc/github/oauth", "path to token to access github repo") - diffCmd.Flags().StringVarP(&githubUser, "github-user", "", "", "github user name when comments in github") - diffCmd.Flags().StringVarP(&githubCommentPrefix, "github-comment-prefix", "", "", "specific comment flag you provided") - diffCmd.Flags().StringVarP(&qiniuCredential, "qiniu-credential", "", "/etc/qiniuconfig/qiniu.json", "path to credential file to access qiniu cloud") - diffCmd.Flags().StringVarP(&robotName, "robot-name", "", "qiniu-bot", "github user name for coverage robot") - diffCmd.Flags().BoolVarP(&fullDiff, "full-diff", "", false, "when set true,calculate and display full diff coverage between new-profile and base-profile") - - rootCmd.AddCommand(diffCmd) -} - -//goc diff --new-profile=./new.cov --base-profile=./base.cov -//+------------------------------------------------------+---------------+--------------+--------+ -//| File | Base Coverage | New Coverage | Delta | -//+------------------------------------------------------+---------------+--------------+--------+ -//| qiniu.com/kodo/bd/pfd/pfdstg/cursor/mgr.go | 53.5% | 50.5% | -3.0% | -//| qiniu.com/kodo/bd/pfd/pfdstg/svr/getstripe.go | 0.5% | 0.0% | -0.5% | -//| Total | 35.7% | 35.7% | -0.0% | -//+------------------------------------------------------+---------------+--------------+--------+ -func doDiffForLocalProfiles(cmd *cobra.Command, args []string) { - localP, err := cover.ReadFileToCoverList(newProfile) - if err != nil { - logrus.Fatal(err) - } - - baseP, err := cover.ReadFileToCoverList(baseProfile) - if err != nil { - logrus.Fatal(err) - } - - //calculate diff file cov and display - rows := cover.GetDeltaCov(localP, baseP) - rows.Sort() - table := tablewriter.NewWriter(os.Stdout) - table.SetHeader([]string{"File", "Base Coverage", "New Coverage", "Delta"}) - table.SetAutoFormatHeaders(false) - table.SetColumnAlignment([]int{tablewriter.ALIGN_LEFT, tablewriter.ALIGN_CENTER, tablewriter.ALIGN_CENTER, tablewriter.ALIGN_CENTER}) - for _, row := range rows { - table.Append([]string{row.FileName, row.BasePer, row.NewPer, row.DeltaPer}) - } - totalDelta := cover.PercentStr(cover.TotalDelta(localP, baseP)) - table.Append([]string{"Total", baseP.TotalPercentage(), localP.TotalPercentage(), totalDelta}) - table.Render() -} - -func doDiffUnderProw(cmd *cobra.Command, args []string) { - var ( - prNumStr = os.Getenv("PULL_NUMBER") - pullSha = os.Getenv("PULL_PULL_SHA") - baseSha = os.Getenv("PULL_BASE_SHA") - repoOwner = os.Getenv("REPO_OWNER") - repoName = os.Getenv("REPO_NAME") - jobType = os.Getenv("JOB_TYPE") - jobName = os.Getenv("JOB_NAME") - buildStr = os.Getenv("BUILD_NUMBER") - artifacts = os.Getenv("ARTIFACTS") - ) - logrus.Printf("Running coverage for PR = %s; PR commit SHA = %s;base SHA = %s", prNumStr, pullSha, baseSha) - - switch jobType { - case "periodic": - logrus.Printf("job type %s, do nothing", jobType) - case "postsubmit": - logrus.Printf("job type %s, do nothing", jobType) - case "presubmit": - if githubToken == "" { - logrus.Fatalf("github token not provided") - } - prClient := github.NewPrClient(githubToken, repoOwner, repoName, prNumStr, robotName, githubCommentPrefix) - - if qiniuCredential == "" { - logrus.Fatalf("qiniu credential not provided") - } - var qc qiniu.Client - var conf qiniu.Config - files, err := ioutil.ReadFile(*&qiniuCredential) - if err != nil { - logrus.WithError(err).Fatal("Error reading qiniu config file") - } - if err := json.Unmarshal(files, &conf); err != nil { - logrus.Fatal("Error unmarshal qiniu config file") - } - if conf.Bucket == "" { - logrus.Fatal("no qiniu bucket provided") - } - if conf.AccessKey == "" || conf.SecretKey == "" { - logrus.Fatal("either qiniu access key or secret key was not provided") - } - if conf.Domain == "" { - logrus.Fatal("no qiniu bucket domain was provided") - } - qc = qiniu.NewClient(&conf) - - localArtifacts := qiniu.ProfileArtifacts{ - Directory: artifacts, - ProfileName: newProfile, - ChangedProfileName: qiniu.ChangedProfileName, - } - - job := prow.Job{ - JobName: jobName, - BuildId: buildStr, - Org: repoOwner, - RepoName: repoName, - PRNumStr: prNumStr, - PostSubmitJob: prowPostSubmitJob, - LocalProfilePath: newProfile, - PostSubmitCoverProfile: prowProfile, - QiniuClient: qc, - LocalArtifacts: &localArtifacts, - GithubComment: prClient, - FullDiff: fullDiff, - } - if err := job.RunPresubmit(); err != nil { - logrus.Fatalf("run presubmit job failed, err: %v", err) - } - default: - logrus.Printf("Unknown job type: %s, do nothing.", jobType) - } -} diff --git a/cmd/diff_test.go b/cmd/diff_test.go deleted file mode 100644 index d8a6426..0000000 --- a/cmd/diff_test.go +++ /dev/null @@ -1,106 +0,0 @@ -/* - Copyright 2020 Qiniu Cloud (qiniu.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 cmd - -import ( - "bytes" - "fmt" - "io" - "io/ioutil" - "os" - "testing" - - "github.com/sirupsen/logrus" - "github.com/spf13/cobra" - "github.com/stretchr/testify/assert" -) - -type diffFunc func(cmd *cobra.Command, args []string) - -func captureStdout(f diffFunc, cmd *cobra.Command, args []string) string { - r, w, err := os.Pipe() - if err != nil { - logrus.WithError(err).Fatal("os pipe fail") - } - stdout := os.Stdout - os.Stdout = w - defer func() { - os.Stdout = stdout - }() - - f(cmd, args) - w.Close() - - var buf bytes.Buffer - io.Copy(&buf, r) - - return buf.String() -} - -func TestDoDiffForLocalProfiles(t *testing.T) { - items := []struct { - newCovFile string - newProfile string - baseCovFile string - baseProfile string - expectOutput string - }{ - { - newCovFile: "new.cov", - baseCovFile: "base.cov", - newProfile: "mode: atomic\n" + - "qiniu.com/kodo/apiserver/server/main.go:32.49,33.13 1 30\n" + - "qiniu.com/kodo/apiserver/server/main.go:42.49,43.13 1 1\n", - baseProfile: "mode: atomic\n" + - "qiniu.com/kodo/apiserver/server/main.go:32.49,33.13 1 30\n" + - "qiniu.com/kodo/apiserver/server/main.go:42.49,43.13 1 0\n", - expectOutput: `+-----------------------------------------+---------------+--------------+-------+ -| File | Base Coverage | New Coverage | Delta | -+-----------------------------------------+---------------+--------------+-------+ -| qiniu.com/kodo/apiserver/server/main.go | 50.0% | 100.0% | 50.0% | -| Total | 50.0% | 100.0% | 50.0% | -+-----------------------------------------+---------------+--------------+-------+ -`, - }, - } - - for _, tc := range items { - err := ioutil.WriteFile(tc.newCovFile, []byte(tc.newProfile), 0644) - if err != nil { - logrus.WithError(err).Fatalf("write file %s failed", tc.newCovFile) - } - err = ioutil.WriteFile(tc.baseCovFile, []byte(tc.baseProfile), 0644) - if err != nil { - logrus.WithError(err).Fatalf("write file %s failed", tc.baseCovFile) - } - defer func() { - os.Remove(tc.newCovFile) - os.Remove(tc.baseCovFile) - }() - - pwd, err := os.Getwd() - if err != nil { - logrus.WithError(err).Fatalf("get pwd failed") - } - - diffCmd.Flags().Set("new-profile", fmt.Sprintf("%s/%s", pwd, tc.newCovFile)) - diffCmd.Flags().Set("base-profile", fmt.Sprintf("%s/%s", pwd, tc.baseCovFile)) - out := captureStdout(doDiffForLocalProfiles, diffCmd, nil) - assert.Equal(t, out, tc.expectOutput) - } - -} diff --git a/cmd/init.go b/cmd/init.go deleted file mode 100644 index c489f80..0000000 --- a/cmd/init.go +++ /dev/null @@ -1,39 +0,0 @@ -/* - Copyright 2020 Qiniu Cloud (qiniu.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 cmd - -import ( - log "github.com/sirupsen/logrus" - - "github.com/qiniu/goc/pkg/cover" - "github.com/spf13/cobra" -) - -var initCmd = &cobra.Command{ - Use: "init", - Short: "Clear the register information in order to start a new round of tests", - Run: func(cmd *cobra.Command, args []string) { - if res, err := cover.NewWorker(center).InitSystem(); err != nil { - log.Fatalf("call host %v failed, err: %v, response: %v", center, err, string(res)) - } - }, -} - -func init() { - addBasicFlags(initCmd.Flags()) - rootCmd.AddCommand(initCmd) -} diff --git a/cmd/install.go b/cmd/install.go index 5d84569..d027474 100644 --- a/cmd/install.go +++ b/cmd/install.go @@ -1,89 +1,25 @@ -/* - Copyright 2020 Qiniu Cloud (qiniu.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 cmd import ( - "os" - - "github.com/qiniu/goc/pkg/build" - "github.com/qiniu/goc/pkg/cover" - log "github.com/sirupsen/logrus" + "github.com/qiniu/goc/v2/pkg/build" + "github.com/qiniu/goc/v2/pkg/config" "github.com/spf13/cobra" ) var installCmd = &cobra.Command{ - Use: "install", - Short: "Do cover for all go files and execute go install command", - Long: ` -Install command will copy the project code and its necessary dependencies to a temporary directory, then do cover for the target, binaries will be generated to their original place. -`, - Example: ` -# Install all binaries with cover variables injected. The binary will be installed in $GOPATH/bin or $HOME/go/bin if directory existed. -goc install ./... + Use: "install", + Run: installAction, -# Install the current binary with cover variables injected, and set the registry center to http://127.0.0.1:7777. -goc install --center=http://127.0.0.1:7777 - -# Install the current binary with cover variables injected, and set necessary build flags: -ldflags "-extldflags -static" -tags="embed kodo". -goc build --buildflags="-ldflags '-extldflags -static' -tags='embed kodo'" -`, - Run: func(cmd *cobra.Command, args []string) { - wd, err := os.Getwd() - if err != nil { - log.Fatalf("Fail to build: %v", err) - } - runInstall(args, wd) - }, + DisableFlagParsing: true, // install 命令需要用原生 go 的方式处理 flags } func init() { - addBuildFlags(installCmd.Flags()) + installCmd.Flags().StringVarP(&config.GocConfig.Mode, "mode", "", "count", "coverage mode: set, count, atomic, watch") + installCmd.Flags().StringVarP(&config.GocConfig.Host, "host", "", "127.0.0.1:7777", "specify the host of the goc sever") rootCmd.AddCommand(installCmd) } -func runInstall(args []string, wd string) { - gocBuild, err := build.NewInstall(buildFlags, args, wd) - if err != nil { - log.Fatalf("Fail to install: %v", err) - } - // remove temporary directory if needed - defer gocBuild.Clean() - // doCover with original buildFlags, with new GOPATH( tmp:original ) - // in the tmp directory - ci := &cover.CoverInfo{ - Args: buildFlags, - GoPath: gocBuild.NewGOPATH, - Target: gocBuild.TmpDir, - Mode: coverMode.String(), - AgentPort: agentPort.String(), - Center: center, - IsMod: gocBuild.IsMod, - ModRootPath: gocBuild.ModRootPath, - OneMainPackage: false, - GlobalCoverVarImportPath: gocBuild.GlobalCoverVarImportPath, - } - err = cover.Execute(ci) - if err != nil { - log.Fatalf("Fail to install: %v", err) - } - // do install in the temporary directory - err = gocBuild.Install() - if err != nil { - log.Fatalf("Fail to install: %v", err) - } - return +func installAction(cmd *cobra.Command, args []string) { + b := build.NewInstall(cmd, args) + b.Install() } diff --git a/cmd/install_test.go b/cmd/install_test.go deleted file mode 100644 index 5b94c97..0000000 --- a/cmd/install_test.go +++ /dev/null @@ -1,84 +0,0 @@ -/* - Copyright 2020 Qiniu Cloud (qiniu.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 cmd - -import ( - "os" - "os/exec" - "path/filepath" - "strings" - "testing" - "time" - - "github.com/stretchr/testify/assert" -) - -func TestInstalledBinaryForMod(t *testing.T) { - startTime := time.Now() - - workingDir := filepath.Join(baseDir, "../tests/samples/simple_project") - gopath := filepath.Join(baseDir, "../tests/samples/simple_project", "testhome") - - os.Setenv("GOPATH", gopath) - os.Setenv("GO111MODULE", "on") - - buildFlags, buildOutput = "", "" - args := []string{"."} - runInstall(args, workingDir) - - obj := filepath.Join(gopath, "bin", "simple-project") - fInfo, err := os.Lstat(obj) - assert.Equal(t, err, nil, "the binary should be generated.") - assert.Equal(t, startTime.Before(fInfo.ModTime()), true, obj+"new binary should be generated, not the old one") - - cmd := exec.Command("go", "tool", "objdump", "simple-project") - cmd.Dir = workingDir - out, _ := cmd.CombinedOutput() - cnt := strings.Count(string(out), "main.registerSelf") - assert.Equal(t, cnt > 0, true, "main.registerSelf function should be in the binary") - - cnt = strings.Count(string(out), "GoCover") - assert.Equal(t, cnt > 0, true, "GoCover variable should be in the binary") -} - -func TestInstalledBinaryForLegacy(t *testing.T) { - startTime := time.Now() - - workingDir := filepath.Join(baseDir, "../tests/samples/simple_gopath_project/src/qiniu.com/simple_gopath_project") - gopath := filepath.Join(baseDir, "../tests/samples/simple_gopath_project") - - os.Setenv("GOPATH", gopath) - os.Setenv("GO111MODULE", "off") - - buildFlags, buildOutput = "", "" - args := []string{"."} - runInstall(args, workingDir) - - obj := filepath.Join(gopath, "bin", "simple_gopath_project") - fInfo, err := os.Lstat(obj) - assert.Equal(t, err, nil, "the binary should be generated.") - assert.Equal(t, startTime.Before(fInfo.ModTime()), true, obj+"new binary should be generated, not the old one") - - cmd := exec.Command("go", "tool", "objdump", obj) - cmd.Dir = workingDir - out, _ := cmd.CombinedOutput() - cnt := strings.Count(string(out), "main.registerSelf") - assert.Equal(t, cnt > 0, true, "main.registerSelf function should be in the binary") - - cnt = strings.Count(string(out), "GoCover") - assert.Equal(t, cnt > 0, true, "GoCover variable should be in the binary") -} diff --git a/cmd/list.go b/cmd/list.go deleted file mode 100644 index 101b4fe..0000000 --- a/cmd/list.go +++ /dev/null @@ -1,49 +0,0 @@ -/* - Copyright 2020 Qiniu Cloud (qiniu.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 cmd - -import ( - "fmt" - "os" - - log "github.com/sirupsen/logrus" - - "github.com/qiniu/goc/pkg/cover" - "github.com/spf13/cobra" -) - -var listCmd = &cobra.Command{ - Use: "list", - Short: "Lists all the registered services", - Long: "Lists all the registered services", - Example: ` -goc list [flags] -`, - Run: func(cmd *cobra.Command, args []string) { - res, err := cover.NewWorker(center).ListServices() - if err != nil { - log.Fatalf("list failed, err: %v", err) - } - log.Infoln(string(res)) - fmt.Fprint(os.Stdout, string(res)) - }, -} - -func init() { - addBasicFlags(listCmd.Flags()) - rootCmd.AddCommand(listCmd) -} diff --git a/cmd/merge.go b/cmd/merge.go deleted file mode 100644 index 64e6495..0000000 --- a/cmd/merge.go +++ /dev/null @@ -1,76 +0,0 @@ -/* - Copyright 2020 Qiniu Cloud (qiniu.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 cmd - -import ( - log "github.com/sirupsen/logrus" - - "github.com/spf13/cobra" - "golang.org/x/tools/cover" - "k8s.io/test-infra/gopherage/pkg/cov" - "k8s.io/test-infra/gopherage/pkg/util" -) - -var mergeCmd = &cobra.Command{ - Use: "merge [files...]", - Short: "Merge multiple coherent Go coverage files into a single file.", - Long: `merge will merge multiple Go coverage files into a single coverage file. -merge requires that the files are 'coherent', meaning that if they both contain references to the -same paths, then the contents of those source files were identical for the binary that generated -each file. -`, - Run: func(cmd *cobra.Command, args []string) { - runMerge(args, outputMergeProfile) - }, -} - -var outputMergeProfile string - -func init() { - mergeCmd.Flags().StringVarP(&outputMergeProfile, "output", "o", "mergeprofile.cov", "output file") - - rootCmd.AddCommand(mergeCmd) -} - -func runMerge(args []string, output string) { - if len(args) == 0 { - log.Fatalln("Expected at least one coverage file.") - return - } - - profiles := make([][]*cover.Profile, len(args)) - for _, path := range args { - profile, err := util.LoadProfile(path) - if err != nil { - log.Fatalf("failed to open %s: %v", path, err) - return - } - profiles = append(profiles, profile) - } - - merged, err := cov.MergeMultipleProfiles(profiles) - if err != nil { - log.Fatalf("failed to merge files: %v", err) - return - } - - err = util.DumpProfile(output, merged) - if err != nil { - log.Fatalln(err) - return - } -} diff --git a/cmd/merge_test.go b/cmd/merge_test.go deleted file mode 100644 index afb7302..0000000 --- a/cmd/merge_test.go +++ /dev/null @@ -1,156 +0,0 @@ -/* - Copyright 2020 Qiniu Cloud (qiniu.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 cmd - -import ( - "io/ioutil" - "os" - "path/filepath" - "testing" - - log "github.com/sirupsen/logrus" - "github.com/stretchr/testify/assert" -) - -// use a variable to record if the tested function has failed -// so unittest can only be executed sequential -var fatal = false -var fatalStr string - -type TestLogHook struct{} - -func (h *TestLogHook) Levels() []log.Level { - return []log.Level{log.FatalLevel} -} - -func (h *TestLogHook) Fire(e *log.Entry) error { - fatalStr = e.Message - return nil -} - -func TestMain(m *testing.M) { - // setup - originalExitFunc := log.StandardLogger().ExitFunc - defer func() { - log.StandardLogger().ExitFunc = originalExitFunc - log.StandardLogger().Hooks = make(log.LevelHooks) - }() - - // replace exit function, so log.Fatal wont exit - log.StandardLogger().ExitFunc = func(int) { fatal = true } - // add hook, so fatal string will be recorded - log.StandardLogger().Hooks.Add(&TestLogHook{}) - - code := m.Run() - - os.Exit(code) -} - -func TestMergeNormalProfiles(t *testing.T) { - profileA := filepath.Join(baseDir, "../tests/samples/merge_profile_samples/a.voc") - profileB := filepath.Join(baseDir, "../tests/samples/merge_profile_samples/b.voc") - mergeprofile := filepath.Join(baseDir, "../tests/samples/merge_profile_samples/merge.cov") - - runMerge([]string{profileA, profileB}, mergeprofile) - - contents, err := ioutil.ReadFile(mergeprofile) - assert.NoError(t, err) - assert.Contains(t, string(contents), "qiniu.com/kodo/apiserver/server/main.go:32.49,33.13 1 60") - assert.Contains(t, string(contents), "qiniu.com/kodo/apiserver/server/main.go:42.49,43.13 1 2") - assert.Equal(t, fatal, false) -} - -// test with no profiles -func TestMergeWithNoProfiles(t *testing.T) { - mergeprofile := filepath.Join(baseDir, "../tests/samples/merge_profile_samples/merge.cov") - - // clear fatal string in setup - fatalStr = "" - fatal = false - - runMerge([]string{}, mergeprofile) - - // there is fatal - assert.Equal(t, fatal, true) - assert.Equal(t, fatalStr, "Expected at least one coverage file.") -} - -// pass a non-existed profile to runMerge -func TestWithWrongProfileName(t *testing.T) { - profileA := filepath.Join(baseDir, "../tests/samples/merge_profile_samples/notexist.voc") - mergeprofile := filepath.Join(baseDir, "../tests/samples/merge_profile_samples/merge.cov") - - // clear fatal string in setup - fatalStr = "" - fatal = false - - runMerge([]string{profileA}, mergeprofile) - - // there is fatal - assert.Equal(t, fatal, true) - assert.Contains(t, fatalStr, "failed to open") -} - -// merge two different modes' profiles should fail -func TestMergeTwoDifferentModeProfile(t *testing.T) { - profileA := filepath.Join(baseDir, "../tests/samples/merge_profile_samples/a.voc") - profileSet := filepath.Join(baseDir, "../tests/samples/merge_profile_samples/setmode.voc") - mergeprofile := filepath.Join(baseDir, "../tests/samples/merge_profile_samples/merge.cov") - - // clear fatal string in setup - fatalStr = "" - fatal = false - - runMerge([]string{profileA, profileSet}, mergeprofile) - - // there is fatal - assert.Equal(t, fatal, true) - assert.Contains(t, fatalStr, "mode for qiniu.com/kodo/apiserver/server/main.go mismatches") -} - -// merge two overlaped profiles should fail -func TestMergeTwoOverLapProfile(t *testing.T) { - profileA := filepath.Join(baseDir, "../tests/samples/merge_profile_samples/a.voc") - profileOverlap := filepath.Join(baseDir, "../tests/samples/merge_profile_samples/overlap.voc") - mergeprofile := filepath.Join(baseDir, "../tests/samples/merge_profile_samples/merge.cov") - - // clear fatal string in setup - fatalStr = "" - fatal = false - - runMerge([]string{profileA, profileOverlap}, mergeprofile) - - // there is fatal - assert.Equal(t, fatal, true) - assert.Contains(t, fatalStr, "coverage block mismatch") -} - -// merge empty file should fail -func TestMergeEmptyProfile(t *testing.T) { - profileA := filepath.Join(baseDir, "../tests/samples/merge_profile_samples/empty.voc") - mergeprofile := filepath.Join(baseDir, "../tests/samples/merge_profile_samples/merge.cov") - - // clear fatal string in setup - fatalStr = "" - fatal = false - - runMerge([]string{profileA}, mergeprofile) - - // there is fatal - assert.Equal(t, fatal, true) - assert.Contains(t, fatalStr, "failed to dump profile") -} diff --git a/cmd/profile.go b/cmd/profile.go deleted file mode 100644 index 502372e..0000000 --- a/cmd/profile.go +++ /dev/null @@ -1,112 +0,0 @@ -/* - Copyright 2020 Qiniu Cloud (qiniu.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 cmd - -import ( - "bytes" - "fmt" - "io" - "os" - "path" - - "github.com/qiniu/goc/pkg/cover" - log "github.com/sirupsen/logrus" - "github.com/spf13/cobra" -) - -var profileCmd = &cobra.Command{ - Use: "profile", - Short: "Get coverage profile from service registry center", - Long: `Get code coverage profile for the services under test at runtime.`, - Example: ` -# Get coverage counter from default register center http://127.0.0.1:7777, the result output to stdout. -goc profile - -# Get coverage counter from specified register center, the result output to specified file. -goc profile --center=http://192.168.1.1:8080 --output=./coverage.cov - -# Get coverage counter of several specified services. You can get all available service names from command 'goc list'. Use 'service' and 'address' flag at the same time may cause ambiguity, please use them separately. -goc profile --service=service1,service2,service3 - -# Get coverage counter of several specified addresses. You can get all available addresses from command 'goc list'. Use 'service' and 'address' flag at the same time may cause ambiguity, please use them separately. -goc profile --address=address1,address2,address3 - -# Only get the coverage data of files matching the special patterns -goc profile --coverfile=pattern1,pattern2,pattern3 - -# Force fetching all available profiles. -goc profile --force -`, - Run: func(cmd *cobra.Command, args []string) { - p := cover.ProfileParam{ - Force: force, - Service: svrList, - Address: addrList, - CoverFilePatterns: coverFilePatterns, - SkipFilePatterns: skipFilePatterns, - } - res, err := cover.NewWorker(center).Profile(p) - if err != nil { - log.Fatalf("Goc server %v return an error: %v", center, err) - } - - if output == "" { - fmt.Fprint(os.Stdout, string(res)) - } else { - var dir, filename string = path.Split(output) - if dir != "" { - err = os.MkdirAll(dir, os.ModePerm) - if err != nil { - log.Fatalf("failed to create directory %s, err:%v", dir, err) - } - } - if filename == "" { - output += "coverage.cov" - } - - f, err := os.Create(output) - if err != nil { - log.Fatalf("failed to create file %s, err:%v", output, err) - } - defer f.Close() - _, err = io.Copy(f, bytes.NewReader(res)) - if err != nil { - log.Fatalf("failed to write file: %v, err: %v", output, err) - } - } - }, -} - -var ( - svrList []string // --service flag - addrList []string // --address flag - force bool // --force flag - output string // --output flag - coverFilePatterns []string // --coverfile flag - skipFilePatterns []string // --skipfile flag -) - -func init() { - profileCmd.Flags().StringVarP(&output, "output", "o", "", "download cover profile") - profileCmd.Flags().StringSliceVarP(&svrList, "service", "", nil, "service name to fetch profile, see 'goc list' for all services.") - profileCmd.Flags().StringSliceVarP(&addrList, "address", "", nil, "address to fetch profile, see 'goc list' for all addresses.") - profileCmd.Flags().BoolVarP(&force, "force", "f", false, "force fetching all available profiles") - profileCmd.Flags().StringSliceVarP(&coverFilePatterns, "coverfile", "", nil, "only output coverage data of the files matching the patterns") - profileCmd.Flags().StringSliceVarP(&skipFilePatterns, "skipfile", "", nil, "skip the files matching the patterns when outputing coverage data") - addBasicFlags(profileCmd.Flags()) - rootCmd.AddCommand(profileCmd) -} diff --git a/cmd/register.go b/cmd/register.go deleted file mode 100644 index ab0518b..0000000 --- a/cmd/register.go +++ /dev/null @@ -1,60 +0,0 @@ -/* - Copyright 2020 Qiniu Cloud (qiniu.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 cmd - -import ( - "fmt" - "log" - "os" - - "github.com/qiniu/goc/pkg/cover" - "github.com/spf13/cobra" -) - -var registerCmd = &cobra.Command{ - Use: "register", - Short: "Register a service into service center", - Long: "Register a service into service center", - Example: ` -goc register [flags] -`, - Run: func(cmd *cobra.Command, args []string) { - s := cover.ServiceUnderTest{ - Name: name, - Address: address, - } - res, err := cover.NewWorker(center).RegisterService(s) - if err != nil { - log.Fatalf("register service failed, err: %v", err) - } - fmt.Fprint(os.Stdout, string(res)) - }, -} - -var ( - name string - address string -) - -func init() { - registerCmd.Flags().StringVarP(¢er, "center", "", "http://127.0.0.1:7777", "cover profile host center") - registerCmd.Flags().StringVarP(&name, "name", "n", "", "service name") - registerCmd.Flags().StringVarP(&address, "address", "a", "", "service address") - registerCmd.MarkFlagRequired("name") - registerCmd.MarkFlagRequired("address") - rootCmd.AddCommand(registerCmd) -} diff --git a/cmd/remove.go b/cmd/remove.go deleted file mode 100644 index 6d21eea..0000000 --- a/cmd/remove.go +++ /dev/null @@ -1,58 +0,0 @@ -/* - Copyright 2020 Qiniu Cloud (qiniu.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 cmd - -import ( - "fmt" - "os" - - log "github.com/sirupsen/logrus" - - "github.com/qiniu/goc/pkg/cover" - "github.com/spf13/cobra" -) - -var removeCmd = &cobra.Command{ - Use: "remove", - Short: "Remove the specified service from the register center.", - Long: `Remove the specified service from the register center, after that, goc profile will not collect coverage data from this service anymore`, - Example: ` -# Remove the service 'mongo' from the default register center http://127.0.0.1:7777. -goc remove --service=mongo - -# Remove the service 'http://127.0.0.1:53' from the specified register center. -goc remove --address="http://127.0.0.1:53" --center=http://192.168.1.1:8080 -`, - Run: func(cmd *cobra.Command, args []string) { - p := cover.ProfileParam{ - Service: svrList, - Address: addrList, - } - res, err := cover.NewWorker(center).Remove(p) - if err != nil { - log.Fatalf("call host %v failed, err: %v, response: %v", center, err, string(res)) - } - fmt.Fprint(os.Stdout, string(res)) - }, -} - -func init() { - addBasicFlags(removeCmd.Flags()) - removeCmd.Flags().StringSliceVarP(&svrList, "service", "", nil, "service name to clear profile, see 'goc list' for all services.") - removeCmd.Flags().StringSliceVarP(&addrList, "address", "", nil, "address to clear profile, see 'goc list' for all addresses.") - rootCmd.AddCommand(removeCmd) -} diff --git a/cmd/root.go b/cmd/root.go index 1316cfa..36955b3 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -1,12 +1,9 @@ /* Copyright 2020 Qiniu Cloud (qiniu.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. @@ -17,15 +14,9 @@ package cmd import ( - "os" - "path/filepath" - "runtime" - "strconv" - "time" - - log "github.com/sirupsen/logrus" + "github.com/qiniu/goc/v2/pkg/config" + "github.com/qiniu/goc/v2/pkg/log" "github.com/spf13/cobra" - "github.com/spf13/viper" ) var rootCmd = &cobra.Command{ @@ -37,52 +28,22 @@ Find more information at: https://github.com/qiniu/goc `, PersistentPreRun: func(cmd *cobra.Command, args []string) { - log.SetReportCaller(true) - log.SetLevel(log.InfoLevel) - log.SetFormatter(&log.TextFormatter{ - FullTimestamp: true, - CallerPrettyfier: func(f *runtime.Frame) (string, string) { - dirname, filename := filepath.Split(f.File) - lastelem := filepath.Base(dirname) - filename = filepath.Join(lastelem, filename) - line := strconv.Itoa(f.Line) - return "", "[" + filename + ":" + line + "]" - }, - }) - if debugGoc == false { - // we only need log in debug mode - log.SetLevel(log.FatalLevel) - log.SetFormatter(&log.TextFormatter{ - DisableTimestamp: true, - CallerPrettyfier: func(f *runtime.Frame) (string, string) { - return "", "" - }, - }) - } + log.DisplayGoc() + // init logger + log.NewLogger() }, - PersistentPostRun: func(cmd *cobra.Command, args []string) { - if debugInCISyncFile != "" { - f, err := os.Create(debugInCISyncFile) - if err != nil { - log.Fatalln(err) - } - defer f.Close() - time.Sleep(5 * time.Second) - } + PersistentPostRun: func(cmd *cobra.Command, args []string) { + log.Sync() }, } func init() { - rootCmd.PersistentFlags().BoolVar(&debugGoc, "debug", false, "run goc in debug mode") - rootCmd.PersistentFlags().StringVar(&debugInCISyncFile, "debugcisyncfile", "", "internal use only, no explain") - rootCmd.PersistentFlags().MarkHidden("debugcisyncfile") - viper.BindPFlags(rootCmd.PersistentFlags()) + rootCmd.PersistentFlags().BoolVar(&config.GocConfig.Debug, "debug", false, "run goc in debug mode") } // Execute the goc tool func Execute() { if err := rootCmd.Execute(); err != nil { - log.Fatalln(err) } } diff --git a/cmd/run.go b/cmd/run.go deleted file mode 100644 index f78207c..0000000 --- a/cmd/run.go +++ /dev/null @@ -1,103 +0,0 @@ -/* - Copyright 2020 Qiniu Cloud (qiniu.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 cmd - -import ( - "fmt" - "io/ioutil" - "net" - "os" - - "github.com/qiniu/goc/pkg/build" - "github.com/qiniu/goc/pkg/cover" - log "github.com/sirupsen/logrus" - "github.com/spf13/cobra" -) - -var runCmd = &cobra.Command{ - Use: "run", - Short: "Run covers and runs the named main Go package", - Long: `Run covers and runs the named main Go package, -It is exactly behave as 'go run .' in addition of some internal goc features.`, - Example: ` -goc run . -goc run . [--buildflags] [--exec] [--arguments] -`, - Run: func(cmd *cobra.Command, args []string) { - wd, err := os.Getwd() - if err != nil { - log.Fatalf("Fail to build: %v", err) - } - gocBuild, err := build.NewBuild(buildFlags, args, wd, buildOutput) - if err != nil { - log.Fatalf("Fail to run: %v", err) - } - gocBuild.GoRunExecFlag = goRunExecFlag - gocBuild.GoRunArguments = goRunArguments - defer gocBuild.Clean() - - server := cover.NewMemoryBasedServer() // only save services in memory - - // start goc server - var l = newLocalListener() - go func() { - err = server.Route(ioutil.Discard).RunListener(l) - if err != nil { - log.Fatalf("Start goc server failed: %v", err) - } - }() - gocServer := fmt.Sprintf("http://%s", l.Addr().String()) - fmt.Printf("[goc] goc server started: %s \n", gocServer) - - // execute covers for the target source with original buildFlags and new GOPATH( tmp:original ) - ci := &cover.CoverInfo{ - Args: buildFlags, - GoPath: gocBuild.NewGOPATH, - Target: gocBuild.TmpDir, - Mode: coverMode.String(), - Center: gocServer, - AgentPort: "", - IsMod: gocBuild.IsMod, - ModRootPath: gocBuild.ModRootPath, - OneMainPackage: true, // go run is similar with go build, build only one main package - GlobalCoverVarImportPath: gocBuild.GlobalCoverVarImportPath, - } - err = cover.Execute(ci) - if err != nil { - log.Fatalf("Fail to run: %v", err) - } - - if err := gocBuild.Run(); err != nil { - log.Fatalf("Fail to run: %v", err) - } - }, -} - -func init() { - addRunFlags(runCmd.Flags()) - rootCmd.AddCommand(runCmd) -} - -func newLocalListener() net.Listener { - l, err := net.Listen("tcp", "127.0.0.1:0") - if err != nil { - if l, err = net.Listen("tcp6", "[::1]:0"); err != nil { - log.Fatalf("failed to listen on a port: %v", err) - } - } - return l -} diff --git a/cmd/server.go b/cmd/server.go index 36d5b5e..4b74218 100644 --- a/cmd/server.go +++ b/cmd/server.go @@ -1,54 +1,27 @@ -/* - Copyright 2020 Qiniu Cloud (qiniu.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 cmd import ( - "github.com/qiniu/goc/pkg/cover" + "github.com/qiniu/goc/v2/pkg/config" + "github.com/qiniu/goc/v2/pkg/server" "github.com/spf13/cobra" - "log" ) var serverCmd = &cobra.Command{ - Use: "server", - Short: "Start a service registry center", - Long: `Start a service registry center.`, - Example: ` -# Start a service registry center, default port :7777. -goc server + Use: "server", + Short: "start a service registry center", + Long: "start a service registry center", + Example: "", -# Start a service registry center with port :8080. -goc server --port=:8080 - -# Start a service registry center with localhost:8080. -goc server --port=localhost:8080 -`, - Run: func(cmd *cobra.Command, args []string) { - server, err := cover.NewFileBasedServer(localPersistence) - if err != nil { - log.Fatalf("New file based server failed, err: %v", err) - } - server.Run(port) - }, + Run: serve, } -var port, localPersistence string - func init() { - serverCmd.Flags().StringVarP(&port, "port", "", ":7777", "listen port to start a coverage host center") - serverCmd.Flags().StringVarP(&localPersistence, "local-persistence", "", "_svrs_address.txt", "the file to save services address information") + // serverCmd.Flags().IntVarP(&config.GocConfig.Port, "port", "", 7777, "listen port to start a coverage host center") + // serverCmd.Flags().StringVarP(&config.GocConfig.StorePath, "storepath", "", "goc.store", "the file to save all goc server information") + serverCmd.Flags().StringVarP(&config.GocConfig.Host, "host", "", "127.0.0.1:7777", "specify the host of the goc server") rootCmd.AddCommand(serverCmd) } + +func serve(cmd *cobra.Command, args []string) { + server.RunGocServerUntilExit(config.GocConfig.Host) +} diff --git a/cmd/version.go b/cmd/version.go deleted file mode 100644 index 5345341..0000000 --- a/cmd/version.go +++ /dev/null @@ -1,51 +0,0 @@ -/* - Copyright 2020 Qiniu Cloud (qiniu.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 cmd - -import ( - "fmt" - "runtime/debug" - - "github.com/spf13/cobra" -) - -// the version value will be injected when publishing -var version = "Unstable" - -var versionCmd = &cobra.Command{ - Use: "version", - Short: "Print the goc version information", - Example: ` -# Print the client and server versions for the current context -goc version - `, - Run: func(cmd *cobra.Command, args []string) { - // if it is "Unstable", means user build local or with go get - if version == "Unstable" { - if info, ok := debug.ReadBuildInfo(); ok { - fmt.Println(info.Main.Version) - } - } else { - // otherwise the value is injected in CI - fmt.Println(version) - } - }, -} - -func init() { - rootCmd.AddCommand(versionCmd) -} diff --git a/cmd/watch.go b/cmd/watch.go new file mode 100644 index 0000000..427e88b --- /dev/null +++ b/cmd/watch.go @@ -0,0 +1,25 @@ +package cmd + +import ( + "github.com/qiniu/goc/v2/pkg/config" + cli "github.com/qiniu/goc/v2/pkg/watch" + "github.com/spf13/cobra" +) + +var watchCmd = &cobra.Command{ + Use: "watch", + Short: "watch for profile's real time update", + Long: "watch for profile's real time update", + Example: "", + + Run: watch, +} + +func init() { + watchCmd.Flags().StringVarP(&config.GocConfig.Host, "host", "", "127.0.0.1:7777", "specify the host of the goc server") + rootCmd.AddCommand(watchCmd) +} + +func watch(cmd *cobra.Command, args []string) { + cli.Watch() +} diff --git a/codecov.yaml b/codecov.yaml deleted file mode 100644 index 42f72f4..0000000 --- a/codecov.yaml +++ /dev/null @@ -1,8 +0,0 @@ -comment: - layout: "reach, diff, flags, files" - behavior: new - require_changes: false # if true: only post the comment if coverage changes - require_base: no # [yes :: must have a base report to post] - require_head: yes # [yes :: must have a head report to post] - branches: # branch names that can post comment - - "master" diff --git a/doc/abstract.md b/doc/abstract.md new file mode 100644 index 0000000..bbcd1d1 --- /dev/null +++ b/doc/abstract.md @@ -0,0 +1,14 @@ +# 摘要 - 设计原则 + +goc 的定位是一个专注提升测试体验和项目质量的工具,它不用于生产环境。 + +当用户从 go 切换为 goc 时,**成本应越小越好**。如果是生产环境无法替代的工具,那使用部署再怎么不便,用户也会趋之若鹜。 + +因此 v2 版本在如下: + +1. goc 命令行使用 +2. goc 部署方式(即 agent <-> server 通信方式) + +做了大量重构甚至重写。 + +得益于重写的通信方式,v2 还提供了 watch 模式,为第三方开发自己的实时代码染色系统提供了接口。 \ No newline at end of file diff --git a/doc/how_to_parse_args_and_flags_in_goc.md b/doc/how_to_parse_args_and_flags_in_goc.md new file mode 100644 index 0000000..f90ca31 --- /dev/null +++ b/doc/how_to_parse_args_and_flags_in_goc.md @@ -0,0 +1,16 @@ +# goc 中的参数处理设计 + +## 背景 + +goc build/install/run 有不少人反馈使用起来和 go build/install/run 相比,还是有不少的差异。这种差异导致在日常开发、CI/CD 中替换不便,有些带引号的参数会被改写的面目全非。 + +## 原则 + +goc build/install/run 会尽可能的模仿 go 原生的方式去处理参数。 + +## 主要问题 + +1. goc 使用 cobra 库来组织各个子命令。cobra 对 flag 处理采用的是 posix 风格(两个短横线),和 go 的 flag 处理差异很大(一个短横线)。 +2. go 命令中 args 和 flags 有着严格先后顺序。而 cobra 库对 flags 和 args 的位置没有要求。 +3. 参数中 `[packages]` 有多种组合情况,会影响到插桩的起始位置。 +4. goc 还有自己参数,且需要和**非** goc build/install/run 的子命令保持一致(两个短横线)。 \ No newline at end of file diff --git a/doc/log.md b/doc/log.md new file mode 100644 index 0000000..32033da --- /dev/null +++ b/doc/log.md @@ -0,0 +1,9 @@ +# 日志设计 + +## 酷炫的终端 + +1. 非 debug 模式模仿 devspace: + 1. 支持不同级别 + 2. 不同颜色 + 3. 长时间操作有转圈动画 +2. debug 模式下为常见日志库行为,这里内部选用的是`go.uber.org/zap` \ No newline at end of file diff --git a/doc/protocol.md b/doc/protocol.md new file mode 100644 index 0000000..b5ac041 --- /dev/null +++ b/doc/protocol.md @@ -0,0 +1,88 @@ +# 通信协议设计 + +## 背景 + +v1 版本中,被插桩的服务会暴露一个 HTTP 接口,由 goc server 来访问获取覆盖率。 + +该方式要求被插桩的服务要有一个外界可访问的 ip + port。 + +如果被测服务躲在 NAT 网络下,该方式就不可行了,典型的就是被测服务由 docker 拉起,而 goc server 部署在另外的网络。 + +## 新设计选择 + +新设计只需要暴露 goc server 的地址,由插桩服务发起连接,然后保持长连接,在该长连接上构建 goc 自己的业务逻辑。 + +### 自行设计 TCP 应用层协议 + +go 语言做网络编程非常适合,非阻塞地处理“粘包”也不麻烦。但设计出来不管是纯二进制的、还是类似 HTTP 的,都不会是通用协议,后续维护和扩展估计是个大坑。 + +### websocket + net/rpc + +与 `websocket + jsonrpc2` 的区别就是没有流式调用,纯 rpc 调用。 + +在这种模式下,agent 和 goc server 的角色和 rpc 中的角色并不对应。agent 是 rpc server, goc server 是 rpc client。由于 websocket 是长连接,上述角色的倒换是可行的。 + +1. goc server 发起获取覆盖率 rpc,agent 响应 rpc,goc server 汇总覆盖率 +2. watch 模式下,agent 再开一条 websocket 连接到 goc server,这条连接中角色不再颠倒,goc server 就是 rpc server + +### websocket + jsonrpc2 + +websocket + jsonrpc2 有流式调用,消息边界。非常适合 + +我找到 `github.com/goriila/websocket` 和 `github.com/sourcegraph/jsonrpc2` 库,后者 import 了前者,前者没有 import 任何其它外部库,全是标准库。把两个库的代码合并一下:`github.com/lyyyuna/jsonrpc2` 就是一个无任何外部库引用的 jsonrpc 实现。 + +这非常适合由插桩代码来使用,因为该库没有再引用其它库,**不会污染原服务的依赖关系**。 + +### gRPC + +老实说 gRPC 在这里更适合作为通信协议来使用,更快更通用,流式调用也有,上一小节的 `github.com/sourcegraph/jsonrpc2` 使用广度就很低。 + +但 gRPC 的 go 实现有一个很大的缺点,用了一些非标准库,且有版本依赖。我们不清楚原服务是不是有特定 gRPC 要求,或是 goc 插入的 gRPC 库会导致编译依赖冲突,或者是编译后运行冲突。 + +所以不适合。 + +### 结论 + +先使用 websocket + net/rpc 来做吧。 + +## 协议内容 + +### 注册 + +注册信息放入 websocket url 中,例如: + +``` +/v2/internal/ws/rpcstream?cmdline=.%2Fcmd&hostname=nuc&pid=1699804 +``` + +注册信息为: + +1. 完整的命令行 +2. hostname +3. 进程 PID + +goc server 再加上 remote ip 对四个元信息生成一个唯一 hash id,作为该 agent 的 ID。 + +### 获取覆盖率 + +``` +GocAgent.GetProfile + +ProfileReq: getprofile + +``` + +### 清空覆盖率 + +``` +GocAgent.ResetProfile + +ProfileReq: resetprofile + +``` + +### watch + +### 异常处理 + +goc server 端遇到 err 就关闭对应 agent 的 websocket 连接。 \ No newline at end of file diff --git a/doc/return_error_or_fatal.md b/doc/return_error_or_fatal.md new file mode 100644 index 0000000..0e80760 --- /dev/null +++ b/doc/return_error_or_fatal.md @@ -0,0 +1,16 @@ +# 返回 error 还是原地 fatal + +哪种好呢?在一个纯命令行应用中,及时 fatal,并能在 panic 中打印出堆栈对调试即为有益。 + +若是返回 error,虽然看起来: + +1. 对每种异常处理都定义的很清楚(有明确的错误消息) +2. 写单测也更容易 + +如果函数调用嵌套很深,导致 error 被一层层包裹返回,以至于在最上层拿到 error 时你都分不清到底出错点在哪 -_-,虽然 Go 1.13 的 error wrap 一定程度消减了这个问题,但还是不如 panic 来的好调试。(如果是一个 web 应用,则做法相反,web 的查错主要靠详细的日志,这时候不应鼓励过多的 panic 或 os.Exit(1)) + +而且 goc 并不是一个供大家使用的库,很多 error 没必要往上抛。 + +目前来看 fatal 还是更适合。 + +那如何保障测试质量呢?我们不应被覆盖率所绑架,只要测试用例全面,一样可以保证质量。 \ No newline at end of file diff --git a/docs/images/goc-vscode.gif b/docs/images/goc-vscode.gif deleted file mode 100644 index a1c2312..0000000 Binary files a/docs/images/goc-vscode.gif and /dev/null differ diff --git a/docs/images/intro.gif b/docs/images/intro.gif deleted file mode 100644 index aeef5b2..0000000 Binary files a/docs/images/intro.gif and /dev/null differ diff --git a/docs/images/wechat.png b/docs/images/wechat.png deleted file mode 100644 index 1cc2126..0000000 Binary files a/docs/images/wechat.png and /dev/null differ diff --git a/go.mod b/go.mod index 5359025..759dc88 100644 --- a/go.mod +++ b/go.mod @@ -1,24 +1,23 @@ -module github.com/qiniu/goc +module github.com/qiniu/goc/v2 -go 1.13 +go 1.16 require ( - github.com/gin-gonic/gin v1.6.3 - github.com/google/go-github v17.0.0+incompatible - github.com/hashicorp/go-retryablehttp v0.6.6 - github.com/julienschmidt/httprouter v1.2.0 - github.com/mattn/go-runewidth v0.0.9 // indirect - github.com/olekukonko/tablewriter v0.0.4 - github.com/qiniu/api.v7/v7 v7.5.0 - github.com/sirupsen/logrus v1.6.0 - github.com/spf13/cobra v1.0.0 + github.com/gin-gonic/gin v1.7.2 + github.com/gorilla/websocket v1.4.2 + github.com/k0kubun/go-ansi v0.0.0-20180517002512-3bf9e2903213 + github.com/mattn/go-colorable v0.1.8 // indirect + github.com/mattn/go-isatty v0.0.13 // indirect + github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d + github.com/spf13/cobra v1.1.3 github.com/spf13/pflag v1.0.5 - github.com/spf13/viper v1.6.2 - github.com/stretchr/testify v1.5.1 github.com/tongjingran/copy v1.4.2 - golang.org/x/mod v0.3.0 - golang.org/x/net v0.0.0-20200625001655-4c5254603344 - golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d - golang.org/x/tools v0.0.0-20200730221956-1ac65761fe2c - k8s.io/test-infra v0.0.0-20200511080351-8ac9dbfab055 + go.uber.org/zap v1.17.0 + golang.org/x/mod v0.4.2 + golang.org/x/sys v0.0.0-20210608053332-aa57babbf139 // indirect + golang.org/x/tools v0.1.3 + k8s.io/kubectl v0.21.2 + k8s.io/test-infra v0.0.0-20210618100605-34aa2f2aa75b ) + +replace k8s.io/client-go => k8s.io/client-go v0.21.1 diff --git a/go.sum b/go.sum index 9682ae1..a252527 100644 --- a/go.sum +++ b/go.sum @@ -1,6 +1,8 @@ bazil.org/fuse v0.0.0-20160811212531-371fbbdaa898/go.mod h1:Xbm+BRKSBEpa4q4hTSxohYNQpsxXPbPry4JJWOB3LB8= bazil.org/fuse v0.0.0-20180421153158-65cc252bf669/go.mod h1:Xbm+BRKSBEpa4q4hTSxohYNQpsxXPbPry4JJWOB3LB8= +cloud.google.com/go v0.25.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.30.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.39.0/go.mod h1:rVLT6fkc8chs9sfPtFc1SBH6em7n+ZoXaG+87tDISts= @@ -12,72 +14,141 @@ cloud.google.com/go v0.44.3/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxK 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.47.0/go.mod h1:5p3Ky/7f3N10VBkhuR5LFtddroTiMyjZV/Kj5qOQFxU= +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.55.0/go.mod h1:ZHmoY+/lIMNkN2+fBmuTiqZ4inFhvQad8ft7MT8IV5Y= +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.60.0/go.mod h1:yw2G51M9IfRboUH61Us8GqCeF1PzPblB823Mn2q2eAU= +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.66.0/go.mod h1:dgqGAjKCDxyhGTtC9dAREQGUJpkceNm1yt590Qno0Ko= 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/logging v1.0.0/go.mod h1:V1cc3ogwobYzQq5f2R7DS/GvRIrI4FKj01Gs5glwAls= 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/pubsub v1.4.0/go.mod h1:LFrqilwgdw4X2cJS9ALgzYmMu+ULyrUN6IHV3CPK4TM= 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.9.0/go.mod h1:m+/etGaqZbylxaNT876QGXqEHp4PR2Rq5GMqICWb9bU= +cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= +cloud.google.com/go/storage v1.10.1-0.20200805182106-fcd132957b02/go.mod h1:bdhVveip9CJX75wUu7ALOTnCSKjv6PHRY0bCeBmePnw= +cloud.google.com/go/storage v1.12.0/go.mod h1:fFLk2dp2oAhDz8QFKwqrjdJvxSp/W2g7nillojlL5Ho= +code.gitea.io/sdk/gitea v0.12.0/go.mod h1:z3uwDV/b9Ls47NGukYM9XhnHtqPh/J+t40lsUrR6JDY= contrib.go.opencensus.io/exporter/aws v0.0.0-20181029163544-2befc13012d0/go.mod h1:uu1P0UCM/6RbsMrgPa98ll8ZcHM858i/AD06a9aLRCA= contrib.go.opencensus.io/exporter/ocagent v0.4.12/go.mod h1:450APlNTSR6FrvC3CTRqYosuDstRB9un7SOx2k/9ckA= contrib.go.opencensus.io/exporter/ocagent v0.5.0/go.mod h1:ImxhfLRpxoYiSq891pBrLVhN+qmP8BTVvdH2YLs7Gl0= +contrib.go.opencensus.io/exporter/ocagent v0.6.0/go.mod h1:zmKjrJcdo0aYcVS7bmEeSEBLPA9YJp5bjrofdU3pIXs= contrib.go.opencensus.io/exporter/prometheus v0.1.0/go.mod h1:cGFniUXGZlKRjzOyuZJ6mgB+PgBcCIa79kEKR8YCW+A= contrib.go.opencensus.io/exporter/stackdriver v0.12.1/go.mod h1:iwB6wGarfphGGe/e5CWqyUk/cLzKnWsOKPVW3no6OTw= contrib.go.opencensus.io/exporter/stackdriver v0.12.8/go.mod h1:XyyafDnFOsqoxHJgTFycKZMrRUrPThLh2iYTJF6uoO0= +contrib.go.opencensus.io/exporter/stackdriver v0.12.9-0.20191108183826-59d068f8d8ff/go.mod h1:XyyafDnFOsqoxHJgTFycKZMrRUrPThLh2iYTJF6uoO0= +contrib.go.opencensus.io/exporter/stackdriver v0.13.1/go.mod h1:z2tyTZtPmQ2HvWH4cOmVDgtY+1lomfKdbLnkJvZdc8c= +contrib.go.opencensus.io/exporter/zipkin v0.1.1/go.mod h1:GMvdSl3eJ2gapOaLKzTKE3qDgUkJ86k9k3yY2eqwkzc= contrib.go.opencensus.io/integrations/ocsql v0.1.4/go.mod h1:8DsSdjz3F+APR+0z0WkU1aRorQCFfRxvqjUUPMbF3fE= contrib.go.opencensus.io/resource v0.1.1/go.mod h1:F361eGI91LCmW1I/Saf+rX0+OFcigGlFvXwEGEnkRLA= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg= git.apache.org/thrift.git v0.12.0/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg= github.com/Azure/azure-amqp-common-go/v2 v2.1.0/go.mod h1:R8rea+gJRuJR6QxTir/XuEd+YuKoUiazDC/N96FiDEU= +github.com/Azure/azure-pipeline-go v0.1.8/go.mod h1:XA1kFWRVhSK+KNFiOhfv83Fv8L9achrP7OxIzeTn1Yg= +github.com/Azure/azure-pipeline-go v0.1.9/go.mod h1:XA1kFWRVhSK+KNFiOhfv83Fv8L9achrP7OxIzeTn1Yg= github.com/Azure/azure-pipeline-go v0.2.1/go.mod h1:UGSo8XybXnIGZ3epmeBw7Jdz+HiUVpqIlpz/HKHylF4= +github.com/Azure/azure-pipeline-go v0.2.2/go.mod h1:4rQ/NZncSvGqNkkOsNpOU1tgoNuIlp9AfUH5G1tvCHc= github.com/Azure/azure-sdk-for-go v16.2.1+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= +github.com/Azure/azure-sdk-for-go v19.1.1+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= +github.com/Azure/azure-sdk-for-go v21.1.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= +github.com/Azure/azure-sdk-for-go v28.1.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= github.com/Azure/azure-sdk-for-go v29.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= github.com/Azure/azure-sdk-for-go v30.1.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= github.com/Azure/azure-sdk-for-go v35.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= github.com/Azure/azure-sdk-for-go v38.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= +github.com/Azure/azure-sdk-for-go v42.3.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= github.com/Azure/azure-service-bus-go v0.9.1/go.mod h1:yzBx6/BUGfjfeqbRZny9AQIbIe3AcV9WZbAdpkoXOa0= +github.com/Azure/azure-storage-blob-go v0.0.0-20190123011202-457680cc0804/go.mod h1:oGfmITT1V6x//CswqY2gtAHND+xIP64/qL7a5QJix0Y= github.com/Azure/azure-storage-blob-go v0.8.0/go.mod h1:lPI3aLPpuLTeUwh1sViKXFxwl2B6teiRqI0deQUvsw0= +github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 h1:w+iIsaOQNcT7OZ575w+acHgRric5iCyQh+xv+KJ4HB8= github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= github.com/Azure/go-autorest v10.8.1+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= +github.com/Azure/go-autorest v10.15.5+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= +github.com/Azure/go-autorest v11.1.2+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= github.com/Azure/go-autorest v12.0.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= +github.com/Azure/go-autorest v14.1.1+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= +github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= +github.com/Azure/go-autorest/autorest v0.1.0/go.mod h1:AKyIcETwSUFxIcs/Wnq/C+kwCtlEYGUVd7FPNb2slmg= github.com/Azure/go-autorest/autorest v0.2.0/go.mod h1:AKyIcETwSUFxIcs/Wnq/C+kwCtlEYGUVd7FPNb2slmg= github.com/Azure/go-autorest/autorest v0.9.0/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI= github.com/Azure/go-autorest/autorest v0.9.3/go.mod h1:GsRuLYvwzLjjjRoWEIyMUaYq8GNUx2nRB378IPt/1p0= github.com/Azure/go-autorest/autorest v0.9.6/go.mod h1:/FALq9T/kS7b5J5qsQ+RSTUdAmGFqi0vUdVNNx8q630= +github.com/Azure/go-autorest/autorest v0.10.2/go.mod h1:/FALq9T/kS7b5J5qsQ+RSTUdAmGFqi0vUdVNNx8q630= +github.com/Azure/go-autorest/autorest v0.11.12/go.mod h1:eipySxLmqSyC5s5k1CLupqet0PSENBEDP93LQ9a8QYw= github.com/Azure/go-autorest/autorest/adal v0.1.0/go.mod h1:MeS4XhScH55IST095THyTxElntu7WqB7pNbZo8Q5G3E= github.com/Azure/go-autorest/autorest/adal v0.5.0/go.mod h1:8Z9fGy2MpX0PvDjB1pEgQTmVqjGhiHBW7RJJEciWzS0= github.com/Azure/go-autorest/autorest/adal v0.8.0/go.mod h1:Z6vX6WXXuyieHAXwMj0S6HY6e6wcHn37qQMBQlvY3lc= github.com/Azure/go-autorest/autorest/adal v0.8.1/go.mod h1:ZjhuQClTqx435SRJ2iMlOxPYt3d2C/T/7TiQCVZSn3Q= github.com/Azure/go-autorest/autorest/adal v0.8.2/go.mod h1:ZjhuQClTqx435SRJ2iMlOxPYt3d2C/T/7TiQCVZSn3Q= +github.com/Azure/go-autorest/autorest/adal v0.8.3/go.mod h1:ZjhuQClTqx435SRJ2iMlOxPYt3d2C/T/7TiQCVZSn3Q= +github.com/Azure/go-autorest/autorest/adal v0.9.5/go.mod h1:B7KF7jKIeC9Mct5spmyCB/A8CG/sEz1vwIRGv/bbw7A= +github.com/Azure/go-autorest/autorest/azure/auth v0.4.2/go.mod h1:90gmfKdlmKgfjUpnCEpOJzsUEjrWDSLwHIG73tSXddM= +github.com/Azure/go-autorest/autorest/azure/cli v0.3.1/go.mod h1:ZG5p860J94/0kI9mNJVoIoLgXcirM2gF5i2kWloofxw= github.com/Azure/go-autorest/autorest/date v0.1.0/go.mod h1:plvfp3oPSKwf2DNjlBjWF/7vwR+cUD/ELuzDCXwHUVA= github.com/Azure/go-autorest/autorest/date v0.2.0/go.mod h1:vcORJHLJEh643/Ioh9+vPmf1Ij9AEBM5FuBIXLmIy0g= +github.com/Azure/go-autorest/autorest/date v0.3.0/go.mod h1:BI0uouVdmngYNUzGWeSYnokU+TrmwEsOqdt8Y6sso74= github.com/Azure/go-autorest/autorest/mocks v0.1.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= github.com/Azure/go-autorest/autorest/mocks v0.2.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= github.com/Azure/go-autorest/autorest/mocks v0.3.0/go.mod h1:a8FDP3DYzQ4RYfVAxAN3SVSiiO77gL2j2ronKKP0syM= +github.com/Azure/go-autorest/autorest/mocks v0.4.1/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k= +github.com/Azure/go-autorest/autorest/to v0.1.0/go.mod h1:GunWKJp1AEqgMaGLV+iocmRAJWqST1wQYhyyjXJ3SJc= github.com/Azure/go-autorest/autorest/to v0.2.0/go.mod h1:GunWKJp1AEqgMaGLV+iocmRAJWqST1wQYhyyjXJ3SJc= github.com/Azure/go-autorest/autorest/to v0.3.0/go.mod h1:MgwOyqaIuKdG4TL/2ywSsIWKAfJfgHDo8ObuUk3t5sA= github.com/Azure/go-autorest/autorest/validation v0.1.0/go.mod h1:Ha3z/SqBeaalWQvokg3NZAlQTalVMtOIAs1aGK7G6u8= +github.com/Azure/go-autorest/autorest/validation v0.2.0/go.mod h1:3EEqHnBxQGHXRYq3HT1WyXAvT7LLY3tl70hw6tQIbjI= github.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6LSNgds39diKLz7Vrc= +github.com/Azure/go-autorest/logger v0.2.0/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8= github.com/Azure/go-autorest/tracing v0.1.0/go.mod h1:ROEEAFwXycQw7Sn3DXNtEedEvdeRAgDr0izn4z5Ij88= github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbtp2fGCgRFtBroKn4Dk= -github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= +github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU= +github.com/BurntSushi/toml v0.3.0/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= 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/DataDog/zstd v1.3.6-0.20190409195224-796139022798/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo= github.com/DataDog/zstd v1.4.1/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo= +github.com/Djarvur/go-err113 v0.0.0-20200410182137-af658d038157/go.mod h1:4UJr5HIiMZrwgkSPdsjy2uOQExX/WEILpIrO9UPGuXs= +github.com/Djarvur/go-err113 v0.1.0/go.mod h1:4UJr5HIiMZrwgkSPdsjy2uOQExX/WEILpIrO9UPGuXs= github.com/GoogleCloudPlatform/cloud-builders/gcs-fetcher v0.0.0-20191203181535-308b93ad1f39/go.mod h1:yfGmCjKuUzk9WzubMlW2zwjhCraIc/J+M40cufdemRM= github.com/GoogleCloudPlatform/cloudsql-proxy v0.0.0-20191009163259-e802c2cb94ae/go.mod h1:mjwGPas4yKduTyubHvD1Atl9r1rUq8DfVy+gkVvZ+oo= github.com/GoogleCloudPlatform/k8s-cloud-provider v0.0.0-20190822182118-27a4ced34534/go.mod h1:iroGtC8B3tQiqtds1l+mgk/BBOrxbqjH+eUfFQYRc14= +github.com/GoogleCloudPlatform/testgrid v0.0.1-alpha.3/go.mod h1:f96W2HYy3tiBNV5zbbRc+NczwYHgG1PHXMQfoEWv680= github.com/GoogleCloudPlatform/testgrid v0.0.7/go.mod h1:lmtHGBL0M/MLbu1tR9BWV7FGZ1FEFIdPqmJiHNCL7y8= +github.com/GoogleCloudPlatform/testgrid v0.0.68/go.mod h1:SIRhudHYGiAUqMwKorBp2Kb5yJKhMq/nEMzFpYlKHVk= github.com/MakeNowJust/heredoc v0.0.0-20170808103936-bb23615498cd/go.mod h1:64YHyfSL2R96J44Nlwm39UHepQbyR5q10x7iYa1ks2E= github.com/Masterminds/goutils v1.1.0/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU= +github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y= github.com/Masterminds/semver/v3 v3.0.3/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs= +github.com/Masterminds/semver/v3 v3.1.0/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs= github.com/Masterminds/sprig/v3 v3.0.2/go.mod h1:oesJ8kPONMONaZgtiHNzUShJbksypC5kWczhZAf6+aU= github.com/Masterminds/vcs v1.13.1/go.mod h1:N09YCmOQr6RLxC6UNHzuVwAdodYbbnycGHSmwVJjcKA= github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA= github.com/Microsoft/go-winio v0.4.15-0.20190919025122-fc70bd9a86b5/go.mod h1:tTuCMEN+UleMWgg9dVx4Hu52b1bJo+59jBh3ajtinzw= github.com/Microsoft/hcsshim v0.8.7/go.mod h1:OHd7sQqRFrYd3RmSgbgji+ctCwkbq2wbEYNSzOYtcBQ= github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= +github.com/NYTimes/gziphandler v1.1.1/go.mod h1:n/CVRwUEOgIxrgPvAQhUUr9oeUtvrhMomdKFjzJNB0c= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= +github.com/OpenPeeDeeP/depguard v1.0.1/go.mod h1:xsIw86fROiiwelg+jB2uM9PiKihMMmUx/1V+TNhjQvM= github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= github.com/PuerkitoBio/purell v1.1.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= @@ -87,57 +158,100 @@ github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d/go.mod h1:H github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo= github.com/Shopify/sarama v1.23.1/go.mod h1:XLH1GYJnLVE0XCr6KdJGVJRTwY30moWNJ4sERjXX6fs= github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= +github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg= github.com/agnivade/levenshtein v1.0.1/go.mod h1:CURSv5d9Uaml+FovSIICkLbAUZ9S4RqaHDIsdSBg7lM= github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7/go.mod h1:6zEj6s6u/ghQa61ZWa/C2Aw3RkjiTBOix7dkqa1VLIs= +github.com/alecthomas/kingpin v2.2.6+incompatible/go.mod h1:59OFYbFVLKQKq+mqrL6Rw5bR0c3ACQaawgXx0QYndlE= 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/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8= github.com/andybalholm/brotli v0.0.0-20190621154722-5f990b63d2d6/go.mod h1:+lx6/Aqd1kLJ1GQfkvOnaZ1WGmLpMpbprPuIOOZX30U= github.com/andygrunwald/go-gerrit v0.0.0-20190120104749-174420ebee6c/go.mod h1:0iuRQp6WJ44ts+iihy5E/WlPqfg5RNeQxOmzRkxCdtk= +github.com/andygrunwald/go-jira v1.13.0/go.mod h1:jYi4kFDbRPZTJdJOVJO4mpMMIwdB+rcZwSO58DzPd2I= github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= +github.com/antihax/optional v0.0.0-20180407024304-ca021399b1a6/go.mod h1:V8iCPQYkqmusNa815XgQio277wI47sdRh1dUOLdyC6Q= github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= +github.com/apex/log v1.1.4/go.mod h1:AlpoD9aScyQfJDVHmLMEcx4oU6LqzkWp4Mg9GdAcEvQ= +github.com/apex/log v1.3.0/go.mod h1:jd8Vpsr46WAe3EZSQ/IUMs2qQD/GOycT5rPWCO1yGcs= +github.com/apex/logs v0.0.4/go.mod h1:XzxuLZ5myVHDy9SAmYpamKKRNApGj54PfYLcFrXqDwo= +github.com/aphistic/golf v0.0.0-20180712155816-02c07f170c5a/go.mod h1:3NqKYiepwy8kCu4PNA+aP7WUV72eXWJeP9/r3/K9aLE= +github.com/aphistic/sweet v0.2.0/go.mod h1:fWDlIh/isSE9n6EPsRmC0det+whmX6dJid3stzu0Xys= +github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= +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/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= github.com/asaskevich/govalidator v0.0.0-20180720115003-f9ffefc3facf/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= github.com/asaskevich/govalidator v0.0.0-20200108200545-475eaeb16496/go.mod h1:oGkLhpf+kjZl6xBf758TQhh5XrAeiJv/7FRz/2spLIg= +github.com/aws/aws-k8s-tester v0.0.0-20190114231546-b411acf57dfe/go.mod h1:1ADF5tAtU1/mVtfMcHAYSm2fPw71DA7fFk0yed64/0I= +github.com/aws/aws-k8s-tester v0.9.3/go.mod h1:nsh1f7joi8ZI1lvR+Ron6kJM2QdCYPU/vFePghSSuTc= github.com/aws/aws-k8s-tester v1.0.0/go.mod h1:NUNd9k43+h9O5tvwL+4N1Ctb//SapmeeFX1G0/2/0Qc= github.com/aws/aws-sdk-go v1.15.11/go.mod h1:mFuSZ37Z9YOHbQEwBWztmVzqXrEkub65tZoCYDt7FT0= github.com/aws/aws-sdk-go v1.15.27/go.mod h1:mFuSZ37Z9YOHbQEwBWztmVzqXrEkub65tZoCYDt7FT0= +github.com/aws/aws-sdk-go v1.15.90/go.mod h1:es1KtYUFs7le0xQ3rOihkuoVD90z7D0fR2Qm4S00/gU= +github.com/aws/aws-sdk-go v1.16.18/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/aws/aws-sdk-go v1.16.26/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/aws/aws-sdk-go v1.19.18/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/aws/aws-sdk-go v1.19.45/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= +github.com/aws/aws-sdk-go v1.20.6/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/aws/aws-sdk-go v1.23.20/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= +github.com/aws/aws-sdk-go v1.23.22/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= +github.com/aws/aws-sdk-go v1.25.11/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/aws/aws-sdk-go v1.27.1/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= +github.com/aws/aws-sdk-go v1.29.32/go.mod h1:1KvfttTE3SPKMpo8g2c6jL3ZKfXtFvKscTgahTma5Xg= +github.com/aws/aws-sdk-go v1.29.34/go.mod h1:1KvfttTE3SPKMpo8g2c6jL3ZKfXtFvKscTgahTma5Xg= github.com/aws/aws-sdk-go v1.30.4/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0= github.com/aws/aws-sdk-go v1.30.5/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0= +github.com/aws/aws-sdk-go v1.30.16/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0= +github.com/aws/aws-sdk-go v1.31.6/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0= +github.com/aws/aws-sdk-go v1.31.12/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0= +github.com/aybabtme/rgbterm v0.0.0-20170906152045-cc83f3b3ce59/go.mod h1:q/89r3U2H7sSsE2t6Kca0lfwTK8JdoNGS/yzM/4iH5I= github.com/bazelbuild/buildtools v0.0.0-20190917191645-69366ca98f89/go.mod h1:5JP0TXzWDHXv8qvxRC4InIazwdyDseBDbzESUMKk1yU= +github.com/bazelbuild/buildtools v0.0.0-20200922170545-10384511ce98/go.mod h1:5JP0TXzWDHXv8qvxRC4InIazwdyDseBDbzESUMKk1yU= github.com/beorn7/perks v0.0.0-20160804104726-4c0e84591b9a/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= 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/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= github.com/bitly/go-simplejson v0.5.0/go.mod h1:cXHtHw4XUPsvGaxgjIAn8PhEWG9NfngEKAMDJEczWVA= +github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84= +github.com/blakesmith/ar v0.0.0-20190502131153-809d4375e1fb/go.mod h1:PkYb9DJNAwrSvRx5DYA+gUcOIgTGVMNkfSCbZM8cWpI= github.com/blang/semver v3.1.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= github.com/blang/semver v3.5.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4= +github.com/bmizerany/perks v0.0.0-20141205001514-d9a9656a3a4b/go.mod h1:ac9efd0D1fsDb3EJvhqgXRbFx7bs2wqZ10HQPeU8U/Q= +github.com/bombsimon/wsl/v2 v2.0.0/go.mod h1:mf25kr/SqFEPhhcxW1+7pxzGlW+hIl/hYTKY95VwV8U= +github.com/bombsimon/wsl/v2 v2.2.0/go.mod h1:Azh8c3XGEJl9LyX0/sFC+CKMc7Ssgua0g+6abzXN4Pg= +github.com/bombsimon/wsl/v3 v3.0.0/go.mod h1:st10JtZYLE4D5sC7b8xV4zTKZwAQjCH/Hy2Pm1FNZIc= +github.com/bombsimon/wsl/v3 v3.1.0/go.mod h1:st10JtZYLE4D5sC7b8xV4zTKZwAQjCH/Hy2Pm1FNZIc= github.com/bshuster-repo/logrus-logstash-hook v0.4.1/go.mod h1:zsTqEiSzDgAa/8GZR7E1qaXrhYNDKBYy5/dWPTIflbk= github.com/bugsnag/bugsnag-go v0.0.0-20141110184014-b1d153021fcd/go.mod h1:2oa8nejYd4cQ/b0hMIopN0lCRxU0bueqREvZLWFrtK8= github.com/bugsnag/osext v0.0.0-20130617224835-0dd3f918b21b/go.mod h1:obH5gd0BsqsP2LwDJ9aOkm/6J86V6lyAXCoQWGw3K50= github.com/bugsnag/panicwrap v0.0.0-20151223152923-e2c28503fcd0/go.mod h1:D/8v3kj0zr8ZAKg1AQ6crr+5VwKN5eIywRkfhyM/+dE= github.com/bwmarrin/snowflake v0.0.0/go.mod h1:NdZxfVWX+oR6y2K0o6qAYv6gIOP9rjG0/E9WsDpxqwE= +github.com/caarlos0/ctrlc v1.0.0/go.mod h1:CdXpj4rmq0q/1Eb44M9zi2nKB0QraNKuRGYGrrHhcQw= +github.com/campoy/unique v0.0.0-20180121183637-88950e537e7e/go.mod h1:9IOqJGCPMSc6E5ydlp5NIonxObaeu/Iub/X03EKPVYo= +github.com/cavaliercoder/go-cpio v0.0.0-20180626203310-925f9528c45e/go.mod h1:oDpT4efm8tSYHXV5tHSdRvBet/b/QzxZ+XyyPehvm3A= github.com/census-instrumentation/opencensus-proto v0.2.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/chai2010/gettext-go v0.0.0-20160711120539-c6fed771bfd5/go.mod h1:/iP1qXHoty45bqomnu2LM+VVyAEdWN+vtSHGlQgyxbw= +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/cihub/seelog v0.0.0-20170130134532-f561c5e57575/go.mod h1:9d6lWj8KzO/fd/NrVaLscBKmPigpZpn5YawRPw+e3Yo= github.com/clarketm/json v1.13.4/go.mod h1:ynr2LRfb0fQU34l07csRNBTcivjySLLiY1YzQqKVfdo= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cloudevents/sdk-go v0.0.0-20190509003705-56931988abe3/go.mod h1:j1nZWMLGg3om8SswStBoY6/SHvcLM19MuZqwDtMtmzs= github.com/cloudevents/sdk-go v1.0.0/go.mod h1:3TkmM0cFqkhCHOq5JzzRU/RxRkwzoS8TZ+G448qVTog= +github.com/cloudevents/sdk-go/v2 v2.0.0/go.mod h1:3CTrpB4+u7Iaj6fd7E2Xvm5IxMdRoaAhqaRVnOr2rCU= +github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= github.com/containerd/cgroups v0.0.0-20190919134610-bf292b21730f/go.mod h1:OApqhQ4XNSNC13gXIwDjhOQxjWa/NxkwZXJ1EvqT0ko= github.com/containerd/console v0.0.0-20180822173158-c12b1e7919c1/go.mod h1:Tj/on1eG8kiEhd0+fhSDzsPAFESxzBBvdyEgyryXffw= @@ -151,10 +265,16 @@ github.com/containerd/fifo v0.0.0-20190226154929-a9fb20d87448/go.mod h1:ODA38xgv github.com/containerd/go-runc v0.0.0-20180907222934-5a6d9f37cfa3/go.mod h1:IV7qH3hrUgRmyYrtgEeGWJfWbgcHL9CSRruz2Vqcph0= github.com/containerd/ttrpc v0.0.0-20190828154514-0e0f228740de/go.mod h1:PvCDdDGpgqzQIzDW1TphrGLssLDZp2GuS+X5DkEJB8o= github.com/containerd/typeurl v0.0.0-20180627222232-a93fcdb778cd/go.mod h1:Cm3kwCdlkCfMSHURc+r6fwoGH6/F1hH3S4sg0rLFWPc= +github.com/coreos/bbolt v1.3.1-coreos.6/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= +github.com/coreos/bbolt v1.3.3/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= +github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= +github.com/coreos/etcd v3.3.17+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= +github.com/coreos/go-oidc v0.0.0-20180117170138-065b426bd416/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc= github.com/coreos/go-oidc v2.1.0+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc= +github.com/coreos/go-semver v0.0.0-20180108230905-e214231b295a/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= @@ -165,6 +285,9 @@ github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfc github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/creack/pty v1.1.11 h1:07n33Z8lZxZ2qwegKbObQohDhXDQxiMMz1NOUGYlesw= +github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/cyphar/filepath-securejoin v0.2.2/go.mod h1:FpkQEhXnPnOthhzymB7CGsFk2G9VLXONKD9G7QGMM+4= github.com/davecgh/go-spew v0.0.0-20151105211317-5215b55f46b2/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -172,22 +295,30 @@ 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/daviddengcn/go-colortext v0.0.0-20160507010035-511bcaf42ccd/go.mod h1:dv4zxwHi5C/8AeI+4gX4dCWOIvNi7I6JCSX0HvlKPgE= github.com/deislabs/oras v0.8.1/go.mod h1:Mx0rMSbBNaNfY9hjpccEnxkOqJL6KGjtxNHPLC4G4As= +github.com/denisenkom/go-mssqldb v0.0.0-20190111225525-2fea367d496d/go.mod h1:xN/JuLBIz4bjkxNmByTiV1IbhfnYb6oo99phBn4Eqhc= github.com/denisenkom/go-mssqldb v0.0.0-20191124224453-732737034ffd/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU= github.com/denverdino/aliyungo v0.0.0-20190125010748-a747050bb1ba/go.mod h1:dV8lFg6daOBZbT6/BDGIz6Y3WFGn8juu6G+CQ6LHtl0= github.com/devigned/tab v0.1.1/go.mod h1:XG9mPq0dFghrYvoBF3xdRrJzSTX1b7IQrvaL9mzjeJY= github.com/dgrijalva/jwt-go v0.0.0-20170104182250-a601269ab70c/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= +github.com/dgrijalva/jwt-go/v4 v4.0.0-preview1/go.mod h1:+hnT3ywWDTAFrW5aE+u2Sa/wT555ZqwoCS+pk3p6ry4= +github.com/dgryski/go-gk v0.0.0-20200319235926-a69029f61654/go.mod h1:qm+vckxRlDt0aOla0RYJJVeqHZlWfOm2UIxHaqPB46E= github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= github.com/dimchansky/utfbom v1.1.0/go.mod h1:rO41eb7gLfo8SF1jd9F8HplJm1Fewwi4mQvIirEdv+8= github.com/djherbis/atime v1.0.0/go.mod h1:5W+KBIuTwVGcqjIfaTwt+KSYX1o6uep8dtevevQP/f8= github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E= +github.com/docker/cli v0.0.0-20190925022749-754388324470/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= github.com/docker/cli v0.0.0-20191017083524-a8ff7f821017/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= github.com/docker/cli v0.0.0-20200130152716-5d0cf8839492/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= +github.com/docker/cli v0.0.0-20200210162036-a4bedce16568/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= github.com/docker/distribution v0.0.0-20191216044856-a8371794149d/go.mod h1:0+TTO4EOBfRPhZXAeF1Vu+W3hHZ8eLp8PgKVZlcvtFY= +github.com/docker/distribution v2.6.0-rc.1.0.20180327202408-83389a148052+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= github.com/docker/docker v0.7.3-0.20190327010347-be7ac8be2ae0/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker v1.4.2-0.20180531152204-71cd53e4a197/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/docker v1.4.2-0.20190924003213-a8608b5b67c7/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/docker v1.4.2-0.20200203170920-46ec8731fbce/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker v1.13.1/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/docker-credential-helpers v0.6.3/go.mod h1:WRaJzqw3CTB9bk10avuGsjVBZsD05qeibJ1/TYlvc0Y= github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= github.com/docker/go-metrics v0.0.0-20180209012529-399ea8c73916/go.mod h1:/u0gXw0Gay3ceNrsHubL3BtdOL2fHf93USgMTe0W5dI= @@ -205,110 +336,174 @@ github.com/eapache/go-resiliency v1.2.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5m github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= github.com/elazarl/goproxy v0.0.0-20170405201442-c4fc26588b6e/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= +github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153 h1:yUdfgN0XgIJw7foRItutHYUIhlcKzcSf5vDpdhQAKTc= +github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= github.com/emirpasic/gods v1.12.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o= github.com/envoyproxy/go-control-plane v0.6.9/go.mod h1:SBwIajubJHhxtWwsL9s8ss4safvEdbitLhGGK48rN6g= +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/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5/go.mod h1:a2zkGnVExMxdzMo3M0Hi/3sEU+cWnZpSni0O6/Yb/P0= +github.com/evanphx/json-patch v0.0.0-20190203023257-5858425f7550/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= +github.com/evanphx/json-patch v0.5.2/go.mod h1:ZWS5hhDbVDyob71nXKNL0+PWn6ToqBHMikGIFbs31qQ= github.com/evanphx/json-patch v4.2.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/evanphx/json-patch v4.5.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= +github.com/evanphx/json-patch v4.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= +github.com/evanphx/json-patch v4.11.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d/go.mod h1:ZZMPRZwes7CROmyNKgQzC3XPs6L/G2EJLHddWejkmf4= github.com/fatih/camelcase v1.0.0/go.mod h1:yN2Sb0lFhZJUdVvtELVWefmrXpuZESvPmqwoZc+/fpc= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= +github.com/fatih/structs v1.0.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= +github.com/felixge/fgprof v0.9.1/go.mod h1:7/HK6JFtFaARhIljgP2IV8rJLIoHDoOYoUphsnGvqxE= github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= +github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= github.com/fortytw2/leaktest v1.2.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= github.com/frankban/quicktest v1.8.1/go.mod h1:ui7WezCLWMWxVWr1GETZY3smRy0G4KWq9vcPtJmFl7Y= -github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/fsouza/fake-gcs-server v0.0.0-20180612165233-e85be23bdaa8/go.mod h1:1/HufuJ+eaDf4KTnYdS6HJMGvMRU8d4cYTuu/1QaBbI= +github.com/fsouza/fake-gcs-server v1.19.4/go.mod h1:I0/88nHCASqJJ5M7zVF0zKODkYTcuXFW5J5yajsNJnE= +github.com/fvbommel/sortorder v1.0.1/go.mod h1:uk88iVf1ovNn1iLfgUVU2F9o5eO30ui720w+kxuqRs0= github.com/garyburd/redigo v0.0.0-20150301180006-535138d7bcd7/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05/YaO1SY= github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/ghodss/yaml v0.0.0-20180820084758-c7ce16629ff4/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= -github.com/gin-gonic/gin v1.6.3 h1:ahKqKTFpO5KTPHxWZjEdPScmYaGtLo8Y4DMHoEsnp14= -github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M= +github.com/gin-gonic/gin v1.7.2 h1:Tg03T9yM2xa8j6I3Z3oqLaQRSmKvxPd6g/2HJ6zICFA= +github.com/gin-gonic/gin v1.7.2/go.mod h1:jD2toBW3GZUr5UMcdrwQA10I7RuaFOl/SGeDjXkfUtY= github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= github.com/globalsign/mgo v0.0.0-20180905125535-1ca0a4f7cbcb/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q= github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q= github.com/go-bindata/go-bindata/v3 v3.1.3/go.mod h1:1/zrpXsLD8YDIbhZRqXzm1Ghc7NhEvIN9+Z6R5/xH4I= +github.com/go-critic/go-critic v0.4.1/go.mod h1:7/14rZGnZbY6E38VEGk2kVhoq6itzc1E68facVDK23g= +github.com/go-critic/go-critic v0.4.3/go.mod h1:j4O3D4RoIwRqlZw5jJpx0BNfXWWbpcJoKu5cYSe4YmQ= +github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= 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-ini/ini v1.25.4/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8= +github.com/go-ini/ini v1.46.0/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8= github.com/go-ini/ini v1.55.0/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8= 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-lintpack/lintpack v0.5.2/go.mod h1:NwZuYi2nUHho8XEIZ6SIxihrnPoqBTDqfpXvXAN0sXM= 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-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas= +github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= +github.com/go-logr/logr v0.4.0 h1:K7/B1jt6fIBQVd4Owv2MqGQClcgf0R266+7C/QjRcLc= +github.com/go-logr/logr v0.4.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= github.com/go-logr/zapr v0.1.0/go.mod h1:tabnROwaDl0UNxkVeFRbY8bwB37GwRv0P8lg6aAiEnk= github.com/go-logr/zapr v0.1.1/go.mod h1:tabnROwaDl0UNxkVeFRbY8bwB37GwRv0P8lg6aAiEnk= +github.com/go-logr/zapr v0.4.0/go.mod h1:tabnROwaDl0UNxkVeFRbY8bwB37GwRv0P8lg6aAiEnk= +github.com/go-ole/go-ole v1.2.1/go.mod h1:7FAglXiTm7HKlQRDeOQ6ZNUHidzCWXuZWq/1dTyBNF8= github.com/go-openapi/analysis v0.0.0-20180825180245-b006789cd277/go.mod h1:k70tL6pCuVxPJOHXQ+wIac1FUrvNkHolPie/cLEU6hI= github.com/go-openapi/analysis v0.17.0/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpRoBWb8PVZO0ik= +github.com/go-openapi/analysis v0.17.2/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpRoBWb8PVZO0ik= github.com/go-openapi/analysis v0.18.0/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpRoBWb8PVZO0ik= github.com/go-openapi/analysis v0.19.2/go.mod h1:3P1osvZa9jKjb8ed2TPng3f0i/UY9snX6gxi44djMjk= github.com/go-openapi/analysis v0.19.5/go.mod h1:hkEAkxagaIvIP7VTn8ygJNkd4kAYON2rCu0v0ObL0AU= github.com/go-openapi/errors v0.17.0/go.mod h1:LcZQpmvG4wyF5j4IhA73wkLFQg+QJXOQHVjmcZxhka0= +github.com/go-openapi/errors v0.17.2/go.mod h1:LcZQpmvG4wyF5j4IhA73wkLFQg+QJXOQHVjmcZxhka0= github.com/go-openapi/errors v0.18.0/go.mod h1:LcZQpmvG4wyF5j4IhA73wkLFQg+QJXOQHVjmcZxhka0= github.com/go-openapi/errors v0.19.2/go.mod h1:qX0BLWsyaKfvhluLejVpVNwNRdXZhEbTA4kxxpKBC94= github.com/go-openapi/jsonpointer v0.0.0-20160704185906-46af16f9f7b1/go.mod h1:+35s3my2LFTysnkMfxsJBAMHj/DoqoB9knIWoYG/Vk0= github.com/go-openapi/jsonpointer v0.17.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M= github.com/go-openapi/jsonpointer v0.18.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M= +github.com/go-openapi/jsonpointer v0.19.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M= github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg= github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= github.com/go-openapi/jsonreference v0.0.0-20160704190145-13c6e3589ad9/go.mod h1:W3Z9FmVs9qj+KR4zFKmDPGiLdk1D9Rlm7cyMvf57TTg= github.com/go-openapi/jsonreference v0.17.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I= github.com/go-openapi/jsonreference v0.18.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I= +github.com/go-openapi/jsonreference v0.19.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I= github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc= github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8= github.com/go-openapi/loads v0.17.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU= +github.com/go-openapi/loads v0.17.2/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU= github.com/go-openapi/loads v0.18.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU= github.com/go-openapi/loads v0.19.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU= github.com/go-openapi/loads v0.19.2/go.mod h1:QAskZPMX5V0C2gvfkGZzJlINuP7Hx/4+ix5jWFxsNPs= github.com/go-openapi/loads v0.19.4/go.mod h1:zZVHonKd8DXyxyw4yfnVjPzBjIQcLt0CCsn0N0ZrQsk= github.com/go-openapi/runtime v0.0.0-20180920151709-4f900dc2ade9/go.mod h1:6v9a6LTXWQCdL8k1AO3cvqx5OtZY/Y9wKTgaoP6YRfA= +github.com/go-openapi/runtime v0.17.2/go.mod h1:QO936ZXeisByFmZEO1IS1Dqhtf4QV1sYYFtIq6Ld86Q= github.com/go-openapi/runtime v0.19.0/go.mod h1:OwNfisksmmaZse4+gpV3Ne9AyMOlP1lt4sK4FXt0O64= github.com/go-openapi/runtime v0.19.4/go.mod h1:X277bwSUBxVlCYR3r7xgZZGKVvBd/29gLDlFGtJ8NL4= github.com/go-openapi/spec v0.0.0-20160808142527-6aced65f8501/go.mod h1:J8+jY1nAiCcj+friV/PDoE1/3eeccG9LYBs0tYvLOWc= github.com/go-openapi/spec v0.17.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI= +github.com/go-openapi/spec v0.17.2/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI= github.com/go-openapi/spec v0.18.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI= github.com/go-openapi/spec v0.19.2/go.mod h1:sCxk3jxKgioEJikev4fgkNmwS+3kuYdJtcsZsD5zxMY= github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo= github.com/go-openapi/spec v0.19.4/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo= +github.com/go-openapi/spec v0.19.5/go.mod h1:Hm2Jr4jv8G1ciIAo+frC/Ft+rR2kQDh8JHKHb3gWUSk= github.com/go-openapi/spec v0.19.6/go.mod h1:Hm2Jr4jv8G1ciIAo+frC/Ft+rR2kQDh8JHKHb3gWUSk= github.com/go-openapi/strfmt v0.17.0/go.mod h1:P82hnJI0CXkErkXi8IKjPbNBM6lV6+5pLP5l494TcyU= github.com/go-openapi/strfmt v0.18.0/go.mod h1:P82hnJI0CXkErkXi8IKjPbNBM6lV6+5pLP5l494TcyU= github.com/go-openapi/strfmt v0.19.0/go.mod h1:+uW+93UVvGGq2qGaZxdDeJqSAqBqBdl+ZPMF/cC8nDY= github.com/go-openapi/strfmt v0.19.3/go.mod h1:0yX7dbo8mKIvc3XSKp7MNfxw4JytCfCD6+bY1AVL9LU= +github.com/go-openapi/strfmt v0.19.5/go.mod h1:eftuHTlB/dI8Uq8JJOyRlieZf+WkkxUuk0dgdHXr2Qk= github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dpr1UfpPtxFw+EFuQ41HhCWZfha5jSVRG7C7I= github.com/go-openapi/swag v0.17.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg= +github.com/go-openapi/swag v0.17.2/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg= github.com/go-openapi/swag v0.18.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg= github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= github.com/go-openapi/swag v0.19.7/go.mod h1:ao+8BpOPyKdpQz3AOJfbeEVpLmWAvlT1IfTe5McPyhY= +github.com/go-openapi/validate v0.17.0/go.mod h1:Uh4HdOzKt19xGIGm1qHf/ofbX1YQ4Y+MYsct2VUrAJ4= github.com/go-openapi/validate v0.18.0/go.mod h1:Uh4HdOzKt19xGIGm1qHf/ofbX1YQ4Y+MYsct2VUrAJ4= github.com/go-openapi/validate v0.19.2/go.mod h1:1tRCw7m3jtI8eNWEEliiAqUIcBztB2KDnRCRMUi7GTA= github.com/go-openapi/validate v0.19.5/go.mod h1:8DJv2CVJQ6kGNpFW6eV9N3JviE1C85nY1c2z52x1Gk4= +github.com/go-openapi/validate v0.19.8/go.mod h1:8DJv2CVJQ6kGNpFW6eV9N3JviE1C85nY1c2z52x1Gk4= github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A= github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q= github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no= github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= -github.com/go-playground/validator/v10 v10.2.0 h1:KgJ0snyC2R9VXYN2rneOtQcw5aHQB1Vv0sFl1UcHBOY= -github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI= +github.com/go-playground/validator/v10 v10.4.1 h1:pH2c5ADXtd66mxoE0Zm9SUhxE20r7aM3F26W0hOn+GE= +github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4= +github.com/go-sql-driver/mysql v0.0.0-20160411075031-7ebe0a500653/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= +github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= 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/go-test/deep v1.0.4/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA= +github.com/go-toolsmith/astcast v1.0.0/go.mod h1:mt2OdQTeAQcY4DQgPSArJjHCcOwlX+Wl/kwN+LbLGQ4= +github.com/go-toolsmith/astcopy v1.0.0/go.mod h1:vrgyG+5Bxrnz4MZWPF+pI4R8h3qKRjjyvV/DSez4WVQ= +github.com/go-toolsmith/astequal v0.0.0-20180903214952-dcb477bfacd6/go.mod h1:H+xSiq0+LtiDC11+h1G32h7Of5O3CYFJ99GVbS5lDKY= +github.com/go-toolsmith/astequal v1.0.0/go.mod h1:H+xSiq0+LtiDC11+h1G32h7Of5O3CYFJ99GVbS5lDKY= +github.com/go-toolsmith/astfmt v0.0.0-20180903215011-8f8ee99c3086/go.mod h1:mP93XdblcopXwlyN4X4uodxXQhldPGZbcEJIimQHrkg= +github.com/go-toolsmith/astfmt v1.0.0/go.mod h1:cnWmsOAuq4jJY6Ct5YWlVLmcmLMn1JUPuQIHCY7CJDw= +github.com/go-toolsmith/astinfo v0.0.0-20180906194353-9809ff7efb21/go.mod h1:dDStQCHtmZpYOmjRP/8gHHnCCch3Zz3oEgCdZVdtweU= +github.com/go-toolsmith/astp v0.0.0-20180903215135-0af7e3c24f30/go.mod h1:SV2ur98SGypH1UjcPpCatrV5hPazG6+IfNHbkDXBRrk= +github.com/go-toolsmith/astp v1.0.0/go.mod h1:RSyrtpVlfTFGDYRbrjyWP1pYu//tSFcvdYrA8meBmLI= +github.com/go-toolsmith/pkgload v0.0.0-20181119091011-e9e65178eee8/go.mod h1:WoMrjiy4zvdS+Bg6z9jZH82QXwkcgCBX6nOfnmdaHks= +github.com/go-toolsmith/pkgload v1.0.0/go.mod h1:5eFArkbO80v7Z0kdngIxsRXRMTaX4Ilcwuh3clNrQJc= +github.com/go-toolsmith/strparse v1.0.0/go.mod h1:YI2nUKP9YGZnL/L1/DLFBfixrcjslWct4wyljWhSRy8= +github.com/go-toolsmith/typep v1.0.0/go.mod h1:JSQCQMUPdRlMZFswiq3TGpNp1GMktqkR2Ns5AIQkATU= +github.com/go-toolsmith/typep v1.0.2/go.mod h1:JSQCQMUPdRlMZFswiq3TGpNp1GMktqkR2Ns5AIQkATU= +github.com/go-xmlfmt/xmlfmt v0.0.0-20191208150333-d5b6f63a941b/go.mod h1:aUCEOzzezBEjDBbFBoSiya/gduyIiWYRP6CnSFIV8AM= +github.com/go-yaml/yaml v2.1.0+incompatible/go.mod h1:w2MrLa16VYP0jy6N7M5kHaCkaLENm+P+Tv+MfurjSw0= github.com/gobuffalo/envy v1.6.5/go.mod h1:N+GkhhZ/93bGZc6ZKhJLP6+m+tCNPKwgSpH9kaifseQ= +github.com/gobuffalo/envy v1.7.0/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI= +github.com/gobuffalo/envy v1.7.1/go.mod h1:FurDp9+EDPE4aIUS3ZLyD+7/9fpx7YRt/ukY6jIHf0w= +github.com/gobuffalo/here v0.6.0/go.mod h1:wAG085dHOYqUpf+Ap+WOdrPTp5IYcDAs/x7PLa8Y5fM= github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= github.com/godbus/dbus v0.0.0-20190422162347-ade71ed3457e/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4= +github.com/gofrs/flock v0.0.0-20190320160742-5135e617513b/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU= github.com/gofrs/flock v0.7.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU= github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s= +github.com/gogo/protobuf v0.0.0-20171007142547-342cbe0a0415/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.0.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= @@ -316,6 +511,8 @@ github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zV github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= github.com/gogo/protobuf v1.2.2-0.20190730201129-28a6bbf47e48/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= +github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= github.com/golang/gddo v0.0.0-20190419222130-af0f2af80721/go.mod h1:xEhNfoBDX1hzLm2Nf80qUvZ2sVwoMZ8d6IE2SrsQfh4= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= @@ -323,167 +520,304 @@ github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4er github.com/golang/groupcache v0.0.0-20180513044358-24b0969c4cb7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= 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/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E= 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 h1:qGJ6qTW+x6xX/my+8YUVl4WNpX9B7+/l2tRsHGZ7f2s= 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/protobuf v0.0.0-20161109072736-4bd1920723d7/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 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 h1:87PNWwrRvUSnqS4dlcBU/ftvOIBep4sYuBLlh6rX2wk= 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.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golangci/check v0.0.0-20180506172741-cfe4005ccda2/go.mod h1:k9Qvh+8juN+UKMCS/3jFtGICgW8O96FVaZsaxdzDkR4= +github.com/golangci/dupl v0.0.0-20180902072040-3e9179ac440a/go.mod h1:ryS0uhF+x9jgbj/N71xsEqODy9BN81/GonCZiOzirOk= +github.com/golangci/errcheck v0.0.0-20181223084120-ef45e06d44b6/go.mod h1:DbHgvLiFKX1Sh2T1w8Q/h4NAI8MHIpzCdnBUDTXU3I0= +github.com/golangci/go-misc v0.0.0-20180628070357-927a3d87b613/go.mod h1:SyvUF2NxV+sN8upjjeVYr5W7tyxaT1JVtvhKhOn2ii8= +github.com/golangci/goconst v0.0.0-20180610141641-041c5f2b40f3/go.mod h1:JXrF4TWy4tXYn62/9x8Wm/K/dm06p8tCKwFRDPZG/1o= +github.com/golangci/gocyclo v0.0.0-20180528134321-2becd97e67ee/go.mod h1:ozx7R9SIwqmqf5pRP90DhR2Oay2UIjGuKheCBCNwAYU= +github.com/golangci/gocyclo v0.0.0-20180528144436-0a533e8fa43d/go.mod h1:ozx7R9SIwqmqf5pRP90DhR2Oay2UIjGuKheCBCNwAYU= +github.com/golangci/gofmt v0.0.0-20190930125516-244bba706f1a/go.mod h1:9qCChq59u/eW8im404Q2WWTrnBUQKjpNYKMbU4M7EFU= +github.com/golangci/golangci-lint v1.23.7/go.mod h1:g/38bxfhp4rI7zeWSxcdIeHTQGS58TCak8FYcyCmavQ= +github.com/golangci/golangci-lint v1.27.0/go.mod h1:+eZALfxIuthdrHPtfM7w/R3POJLjHDfJJw8XZl9xOng= +github.com/golangci/ineffassign v0.0.0-20190609212857-42439a7714cc/go.mod h1:e5tpTHCfVze+7EpLEozzMB3eafxo2KT5veNg1k6byQU= +github.com/golangci/lint-1 v0.0.0-20191013205115-297bf364a8e0/go.mod h1:66R6K6P6VWk9I95jvqGxkqJxVWGFy9XlDwLwVz1RCFg= +github.com/golangci/maligned v0.0.0-20180506175553-b1d89398deca/go.mod h1:tvlJhZqDe4LMs4ZHD0oMUlt9G2LWuDGoisJTBzLMV9o= +github.com/golangci/misspell v0.0.0-20180809174111-950f5d19e770/go.mod h1:dEbvlSfYbMQDtrpRMQU675gSDLDNa8sCPPChZ7PhiVA= +github.com/golangci/misspell v0.3.5/go.mod h1:dEbvlSfYbMQDtrpRMQU675gSDLDNa8sCPPChZ7PhiVA= +github.com/golangci/prealloc v0.0.0-20180630174525-215b22d4de21/go.mod h1:tf5+bzsHdTM0bsB7+8mt0GUMvjCgwLpTapNZHU8AajI= +github.com/golangci/revgrep v0.0.0-20180526074752-d9c87f5ffaf0/go.mod h1:qOQCunEYvmd/TLamH+7LlVccLvUH5kZNhbCgTHoBbp4= +github.com/golangci/revgrep v0.0.0-20180812185044-276a5c0a1039/go.mod h1:qOQCunEYvmd/TLamH+7LlVccLvUH5kZNhbCgTHoBbp4= +github.com/golangci/unconvert v0.0.0-20180507085042-28b1c447d1f4/go.mod h1:Izgrg8RkN3rCIMLGE9CyYmU9pY2Jer6DgANEnZ/L/cQ= github.com/golangplus/bytes v0.0.0-20160111154220-45c989fe5450/go.mod h1:Bk6SMAONeMXrxql8uvOKuAZSu8aM5RUGv+1C6IJaEho= github.com/golangplus/fmt v0.0.0-20150411045040-2a5d6d7d2995/go.mod h1:lJgMEyOkYFkPcDKwRXegd+iM6E7matEszMG5HhwytU8= github.com/golangplus/testing v0.0.0-20180327235837-af21d9c3145e/go.mod h1:0AA//k/eakGydO4jKRoRL2j92ZKSzTgj9tclaCrvXHk= github.com/gomodule/redigo v1.7.0/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4= +github.com/google/btree v0.0.0-20180124185431-e89373fe6b4a/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= 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.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/go-containerregistry v0.0.0-20191010200024-a3d713f9b7f8/go.mod h1:KyKXa9ciM8+lgMXwOVsXi7UxGrsf9mM61Mzs+xKUrKE= github.com/google/go-containerregistry v0.0.0-20200115214256-379933c9c22b/go.mod h1:Wtl/v6YdQxv397EREtzwgd9+Ud7Q5D8XMbi3Zazgkrs= -github.com/google/go-github v17.0.0+incompatible h1:N0LgJ1j65A7kfXrZnUDaYCs/Sf4rEjNlfyDHW9dolSY= +github.com/google/go-containerregistry v0.0.0-20200123184029-53ce695e4179/go.mod h1:Wtl/v6YdQxv397EREtzwgd9+Ud7Q5D8XMbi3Zazgkrs= +github.com/google/go-containerregistry v0.0.0-20200331213917-3d03ed9b1ca2/go.mod h1:pD1UFYs7MCAx+ZLShBdttcaOSbyc8F9Na/9IZLNwJeA= +github.com/google/go-containerregistry v0.1.1/go.mod h1:npTSyywOeILcgWqd+rvtzGWflIPPcBQhYoOONaY4ltM= github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ= +github.com/google/go-github/v27 v27.0.6/go.mod h1:/0Gr8pJ55COkmv+S/yPKCczSkUPIM/LnFyubufRNIS0= +github.com/google/go-github/v28 v28.1.1/go.mod h1:bsqJWQX05omyWVmc00nEUql9mhQyv38lDZ8kPZcQVoM= +github.com/google/go-github/v29 v29.0.3/go.mod h1:CHKiKKPHJ0REzfwc14QMklvtHwCveD0PxlMjLlzAM5E= github.com/google/go-licenses v0.0.0-20191112164736-212ea350c932/go.mod h1:16wa6pRqNDUIhOtwF0GcROVqMeXHZJ7H6eGDFUh5Pfk= -github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASuANWTrk= +github.com/google/go-licenses v0.0.0-20200227160636-0fa8c766a591/go.mod h1:JWeTIGPLQ9gF618ZOdlUitd1gRR/l99WOkHOlmR/UVA= +github.com/google/go-querystring v0.0.0-20170111101155-53e6ce116135/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= github.com/google/go-replayers/grpcreplay v0.1.0/go.mod h1:8Ig2Idjpr6gifRd6pNVggX6TC1Zw6Jx74AKp7QNH2QE= github.com/google/go-replayers/httpreplay v0.1.0/go.mod h1:YKZViNhiGgqdBlUbI2MwGpq4pXxNmhJLPHQ7cv2b5no= github.com/google/gofuzz v0.0.0-20161122191042-44d81051d367/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI= +github.com/google/gofuzz v0.0.0-20170612174753-24818f796faf/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/gofuzz v1.2.1-0.20210504230335-f78f29fc09ea h1:VcIYpAGBae3Z6BVncE0OnTE/ZjlDXqtYhOZky88neLM= +github.com/google/gofuzz v1.2.1-0.20210504230335-f78f29fc09ea/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/licenseclassifier v0.0.0-20190926221455-842c0d70d702/go.mod h1:qsqn2hxC+vURpyBRygGUuinTO42MFRLcsmQ/P8v94+M= +github.com/google/licenseclassifier v0.0.0-20200402202327-879cb1424de0/go.mod h1:qsqn2hxC+vURpyBRygGUuinTO42MFRLcsmQ/P8v94+M= +github.com/google/mako v0.0.0-20190821191249-122f8dcef9e3/go.mod h1:YzLcVlL+NqWnmUEPuhS1LxDDwGO9WNbVlEXaF4IH35g= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian v2.1.1-0.20190517191504-25dcb96d9e51+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= +github.com/google/martian/v3 v3.0.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-20190723021845-34ac40c74b70/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-20200507031123-427632fa3b1c/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200615235658-03e1cf38a040/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-20200905233945-acf8798be1f7/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/rpmpack v0.0.0-20191226140753-aa36bfddb3a0/go.mod h1:RaTPr0KUf2K7fnZYLNDrr8rxAamWs3iNywJLtQ2AzBg= +github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= github.com/google/subcommands v1.0.1/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk= github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.1.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/wire v0.3.0/go.mod h1:i1DMg/Lu8Sz5yYl25iOdmc5CT5qusaa+zmRWs16741s= +github.com/google/wire v0.4.0/go.mod h1:ngWDr9Qvq3yZA10YrxfyGELY/AFWGVpy9c1LTRi1EoU= +github.com/googleapis/gax-go v2.0.0+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY= github.com/googleapis/gax-go v2.0.2+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY= 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/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= +github.com/googleapis/gnostic v0.1.0/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= github.com/googleapis/gnostic v0.2.2/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= github.com/googleapis/gnostic v0.3.1/go.mod h1:on+2t9HRStVgn95RSsFWFz+6Q0Snyqv1awfrALZdbtU= +github.com/googleapis/gnostic v0.4.0/go.mod h1:on+2t9HRStVgn95RSsFWFz+6Q0Snyqv1awfrALZdbtU= +github.com/googleapis/gnostic v0.4.1/go.mod h1:LRhVm6pbyptWbWbuZ38d1eyptfvIytN3ir6b65WBswg= +github.com/googleapis/gnostic v0.5.5/go.mod h1:7+EbHbldMins07ALC74bsA81Ovc97DwqyJO1AENw9kA= +github.com/gookit/color v1.2.4/go.mod h1:AhIE+pS6D4Ql0SQWbBeXPHw7gY0/sjHoA4s/n1KB7xg= github.com/gophercloud/gophercloud v0.1.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8= -github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/goreleaser/goreleaser v0.136.0/go.mod h1:wiKrPUeSNh6Wu8nUHxZydSOVQ/OZvOaO7DTtFqie904= +github.com/goreleaser/nfpm v1.2.1/go.mod h1:TtWrABZozuLOttX2uDlYyECfQX7x5XYkVxhjYcR6G9w= +github.com/goreleaser/nfpm v1.3.0/go.mod h1:w0p7Kc9TAUgWMyrub63ex3M2Mgw88M4GZXoTq5UCb40= github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= github.com/gorilla/csrf v1.6.2/go.mod h1:7tSf8kmjNYr7IWDCYhd3U8Ck34iQ/Yw5CJu7bAkHEGI= github.com/gorilla/handlers v0.0.0-20150720190736-60c7bfde3e33/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ= +github.com/gorilla/handlers v1.4.2/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ= github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/gorilla/mux v1.7.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= +github.com/gorilla/mux v1.7.4/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4= +github.com/gorilla/sessions v1.1.3/go.mod h1:8KCfur6+4Mqcc6S0FEfKuN15Vl5MgXW92AE8ovaJD0w= github.com/gorilla/sessions v1.2.0/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM= github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= +github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/gostaticanalysis/analysisutil v0.0.0-20190318220348-4088753ea4d3/go.mod h1:eEOZF4jCKGi+aprrirO9e7WKB3beBRtWgqGunKl6pKE= +github.com/gostaticanalysis/analysisutil v0.0.3/go.mod h1:eEOZF4jCKGi+aprrirO9e7WKB3beBRtWgqGunKl6pKE= github.com/gosuri/uitable v0.0.4/go.mod h1:tKR86bXuXPZazfOTG1FIzvjIdXzd0mo4Vtn16vt0PJo= +github.com/gotestyourself/gotestyourself v2.2.0+incompatible/go.mod h1:zZKM6oeNM8k+FRljX1mnzVYeS8wiGgQyvST1/GafPbY= github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= github.com/gregjones/httpcache v0.0.0-20190212212710-3befbb6ad0cc/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= +github.com/grpc-ecosystem/go-grpc-middleware v0.0.0-20190222133341-cfaf5686ec79/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= +github.com/grpc-ecosystem/go-grpc-prometheus v0.0.0-20170330212424-2500245aa611/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= +github.com/grpc-ecosystem/grpc-gateway v1.3.0/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw= +github.com/grpc-ecosystem/grpc-gateway v1.4.1/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw= github.com/grpc-ecosystem/grpc-gateway v1.8.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= github.com/grpc-ecosystem/grpc-gateway v1.9.2/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= +github.com/grpc-ecosystem/grpc-gateway v1.9.4/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= +github.com/grpc-ecosystem/grpc-gateway v1.12.1/go.mod h1:8XEsbTttt/W+VvjtQhLACqCisSPWTxCZ7sBRjU6iH9c= +github.com/grpc-ecosystem/grpc-gateway v1.12.2/go.mod h1:8XEsbTttt/W+VvjtQhLACqCisSPWTxCZ7sBRjU6iH9c= github.com/h2non/gock v1.0.9/go.mod h1:CZMcB0Lg5IWnr9bF79pPMg9WeV6WumxQiUJ1UvdO1iE= +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 v0.0.0-20141028054710-7554cd9344ce/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= -github.com/hashicorp/go-cleanhttp v0.5.1 h1:dH3aiDG9Jvb5r5+bYHsikaOUIpcM0xvgMXVoDkXMzJM= github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= -github.com/hashicorp/go-hclog v0.9.2 h1:CG6TE5H9/JXsFWJCfoIVpKFIkFe6ysEuHirp4DxCsHI= github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= +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 v0.0.0-20161216184304-ed905158d874/go.mod h1:JMRHfdO9jKNzS/+BTlxCjKNQHg/jZAft8U7LloJvN7I= +github.com/hashicorp/go-multierror v0.0.0-20171204182908-b7773ae21874/go.mod h1:JMRHfdO9jKNzS/+BTlxCjKNQHg/jZAft8U7LloJvN7I= github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= -github.com/hashicorp/go-retryablehttp v0.6.6 h1:HJunrbHTDDbBb/ay4kxa1n+dLmttUlnP3V9oNE4hmsM= +github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA= +github.com/hashicorp/go-retryablehttp v0.6.4/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY= github.com/hashicorp/go-retryablehttp v0.6.6/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY= +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-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= +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/golang-lru v0.5.3/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= -github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= -github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= +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/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/huandu/xstrings v1.2.0/go.mod h1:DvyZB1rfVYsBIigL8HwpZgxHwXozlTgGqn63UyNX5k4= +github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= github.com/imdario/mergo v0.3.6/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= github.com/imdario/mergo v0.3.7/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= github.com/imdario/mergo v0.3.8/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= +github.com/imdario/mergo v0.3.9/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= +github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/influxdata/influxdb v0.0.0-20161215172503-049f9b42e9a5/go.mod h1:qZna6X/4elxqT3yI9iZYdZrWWdeFOOprn86kgg4+IzY= +github.com/influxdata/tdigest v0.0.0-20181121200506-bf2b5ad3c0a9/go.mod h1:Js0mqiSBE6Ffsg94weZZ2c+v/ciT8QRHFOap7EKDrR0= +github.com/jarcoal/httpmock v1.0.5/go.mod h1:ATjnClrvW/3tijVmpL/va5Z3aAyGvqU3gCT8nX0Txik= github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo= github.com/jcmturner/gofork v0.0.0-20190328161633-dc7c13fece03/go.mod h1:MK8+TM0La+2rjBD4jE12Kj1pCCxK7d2LK/UM3ncEo0o= github.com/jcmturner/gofork v1.0.0/go.mod h1:MK8+TM0La+2rjBD4jE12Kj1pCCxK7d2LK/UM3ncEo0o= +github.com/jenkins-x/go-scm v1.5.65/go.mod h1:MgGRkJScE/rJ30J/bXYqduN5sDPZqZFITJopsnZmTOw= github.com/jenkins-x/go-scm v1.5.79/go.mod h1:PCT338UhP/pQ0IeEeMEf/hoLTYKcH7qjGEKd7jPkeYg= +github.com/jenkins-x/go-scm v1.5.117/go.mod h1:PCT338UhP/pQ0IeEeMEf/hoLTYKcH7qjGEKd7jPkeYg= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jingyugao/rowserrcheck v0.0.0-20191204022205-72ab7603b68a/go.mod h1:xRskid8CManxVta/ALEhJha/pweKBaVG6fWgc0yH25s= +github.com/jinzhu/gorm v0.0.0-20170316141641-572d0a0ab1eb/go.mod h1:Vla75njaFJ8clLU1W44h34PjIkijhjHIYnZxMqCdxqo= github.com/jinzhu/gorm v1.9.12/go.mod h1:vhTjlKSJUTWNtcbQtrMBFCxy7eXTzeCAzfL5fBZT/Qs= +github.com/jinzhu/inflection v0.0.0-20190603042836-f5c5f50e6090/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= github.com/jinzhu/now v1.0.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= github.com/jinzhu/now v1.1.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= +github.com/jirfag/go-printf-func-name v0.0.0-20191110105641-45db9963cdd3/go.mod h1:HEWGJkRDzjJY2sqdDwxccsGicWEf9BQOZsq2tV+xzM0= +github.com/jirfag/go-printf-func-name v0.0.0-20200119135958-7558a9eaa5af/go.mod h1:HEWGJkRDzjJY2sqdDwxccsGicWEf9BQOZsq2tV+xzM0= github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= github.com/jmespath/go-jmespath v0.0.0-20160803190731-bd40a432e4c7/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= github.com/jmespath/go-jmespath v0.3.0/go.mod h1:9QtRXoHjLGCJ5IBSaohpXITPlowMeeYCZ7fLUTSywik= +github.com/jmoiron/sqlx v1.2.1-0.20190826204134-d7d95172beb5/go.mod h1:1FEQNm3xlJgrMD+FBdI9+xvCksHtbpVBBw5dYhBSsks= github.com/joefitzgerald/rainbow-reporter v0.1.0/go.mod h1:481CNgqmVHQZzdIbN52CupLJyoVwB10FQ/IQlF1pdL8= github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg= +github.com/jonboulle/clockwork v0.0.0-20141017032234-72f9bd7c4e0c/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= +github.com/jpillora/backoff v0.0.0-20180909062703-3050d21c67d7/go.mod h1:2iMrUgbbvHEiQClaW2NsSzMyGHqN+rDFqY705q49KG0= +github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= github.com/json-iterator/go v0.0.0-20180612202835-f2b4162afba3/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v0.0.0-20180701071628-ab8a2e0c74be/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/json-iterator/go v1.1.5/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/json-iterator/go v1.1.9 h1:9yzud/Ht36ygwatGx56VwCZtlI/2AD15T1X2sjSuGns= github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +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/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= +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 h1:TDTW5Yz1mjftljbcKqRcrYhd4XeOoI98t+9HbQbYf7g= 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/k0kubun/go-ansi v0.0.0-20180517002512-3bf9e2903213 h1:qGQQKEcAR99REcMpsXCp3lJ03zYT1PkRd3kQGPn9GVg= +github.com/k0kubun/go-ansi v0.0.0-20180517002512-3bf9e2903213/go.mod h1:vNUNkEQ1e29fT/6vq2aBdFsgNPmy8qMdSay1npru+Sw= +github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8= +github.com/kelseyhightower/envconfig v1.3.0/go.mod h1:cccZRl6mQpaq41TPp5QxidR+Sa3axMbJDNb//FQX6Gg= github.com/kelseyhightower/envconfig v1.4.0/go.mod h1:cccZRl6mQpaq41TPp5QxidR+Sa3axMbJDNb//FQX6Gg= github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= +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.0/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= github.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= github.com/klauspost/compress v1.9.2/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= github.com/klauspost/compress v1.10.2/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= +github.com/klauspost/cpuid v0.0.0-20180405133222-e7e905edc00e/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= +github.com/klauspost/cpuid v1.2.2/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= github.com/klauspost/pgzip v1.2.1/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs= +github.com/knative/build v0.1.2/go.mod h1:/sU74ZQkwlYA5FwYDJhYTy61i/Kn+5eWfln2jDbw3Qo= +github.com/konsorten/go-windows-terminal-sequences v0.0.0-20180402223658-b729f2633dfe/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= 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.2 h1:DB17ag19krx9CFsz4o3enTrPXyIXCl+2iCXH/aMAp9s= github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/konsorten/go-windows-terminal-sequences v1.0.3 h1:CE8S1cTafDpPvMhIxNJKvHsGVBgn1xWYf1NbHQhywc8= github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= 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.0 h1:s5hAObm+yFO5uHYt5dYjxi2rXrsnmRpJx4OYvIWUaQs= github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pty v1.0.0/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA= github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw= -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/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y= github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= +github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.1.1/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= +github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de/go.mod h1:zAbeS9B/r2mtpb6U+EI2rYA5OAXxsYw6wTamcNW+zcE= +github.com/lightstep/tracecontext.go v0.0.0-20181129014701-1757c391b1ac/go.mod h1:Frd2bnT3w5FB5q49ENTfVlztJES+1k/7lyWX2+9gq/M= github.com/lithammer/dedent v1.1.0/go.mod h1:jrXYCQtgg0nJiN+StA2KgR7w6CiQNv9Fd/Z9BP0jIOc= +github.com/logrusorgru/aurora v0.0.0-20181002194514-a7b3b318ed4e/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4= github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= -github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4= github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= @@ -491,38 +825,71 @@ github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs= +github.com/mailru/easyjson v0.7.1-0.20191009090205-6c0755d89d1e/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs= +github.com/maratori/testpackage v1.0.1/go.mod h1:ddKdw+XG0Phzhx8BFDTKgpWP4i7MpApTE5fXSKAqwDU= github.com/markbates/inflect v1.0.4/go.mod h1:1fR9+pO2KHEO9ZRtto13gDwwZaAKstQzferVeWqbgNs= +github.com/markbates/pkger v0.17.1/go.mod h1:0JoVlrol20BSywW79rN3kdFFsE5xYM+rSCQDXbLhiuI= github.com/marstr/guid v1.1.0/go.mod h1:74gB1z2wpxxInTG6yaqA7KrtM0NZ+RbrcqDvYHefzho= +github.com/matoous/godox v0.0.0-20190911065817-5d6d842e92eb/go.mod h1:1BELzlh859Sh1c6+90blK8lbYy0kwQf1bYlBhBysy1s= github.com/mattbaird/jsonpatch v0.0.0-20171005235357-81af80346b1a/go.mod h1:M1qoD/MqPgTZIk0EWKB38wE28ACRfVcn+cU08jyArI0= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ= github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= +github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +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-ieproxy v0.0.0-20190610004146-91bb50d98149/go.mod h1:31jz6HNzdxOmlERGGEc4v/dMssOfmp2p5bT/okiKFFc= +github.com/mattn/go-ieproxy v0.0.0-20190702010315-6dee0af9227d/go.mod h1:31jz6HNzdxOmlERGGEc4v/dMssOfmp2p5bT/okiKFFc= +github.com/mattn/go-ieproxy v0.0.1/go.mod h1:pYabZ6IHcRpFh7vIaLfK7rdcWgFEb3SFJ6/gNWuh88E= +github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= -github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY= 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.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= -github.com/mattn/go-runewidth v0.0.8 h1:3tS41NlGYSmhhe/8fhGRzc+z3AYCw1Fe1WAyLuujKs0= github.com/mattn/go-runewidth v0.0.8/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= -github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0= -github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= github.com/mattn/go-shellwords v1.0.9/go.mod h1:EZzvwXDESEeg03EKmM+RmDnNOPKG4lLtQsUlTZDWQ8Y= +github.com/mattn/go-shellwords v1.0.10/go.mod h1:EZzvwXDESEeg03EKmM+RmDnNOPKG4lLtQsUlTZDWQ8Y= +github.com/mattn/go-sqlite3 v0.0.0-20160514122348-38ee283dabf1/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= +github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= github.com/mattn/go-sqlite3 v2.0.1+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= github.com/mattn/go-zglob v0.0.1/go.mod h1:9fxibJccNxU2cnpIKLRRFA7zX7qhkJIQWBb449FYHOo= +github.com/mattn/go-zglob v0.0.2/go.mod h1:9fxibJccNxU2cnpIKLRRFA7zX7qhkJIQWBb449FYHOo= +github.com/mattn/goveralls v0.0.2/go.mod h1:8d1ZMHsd7fW6IRPKQh46F2WRpyib5/X4FOpevwGNQEw= +github.com/matttproud/golang_protobuf_extensions v1.0.0/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= github.com/maxbrunsfeld/counterfeiter/v6 v6.2.2/go.mod h1:eD9eIE7cdwcMi9rYluz88Jz2VyhSmden33/aXg4oVIY= +github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE= +github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d h1:5PJl274Y63IEHC+7izoQE9x6ikvDFZS2mDVS3drnohI= +github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE= github.com/mholt/archiver/v3 v3.3.0/go.mod h1:YnQtqsp+94Rwd0D/rk5cnLrxusUBUXg+08Ebtr1Mqao= +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/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw= +github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-ps v0.0.0-20190716172923-621e5597135b/go.mod h1:r1VsdOzOPt1ZSrGZWFoNhsAedKnEd6r9Np1+5blZCWk= +github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= +github.com/mitchellh/go-wordwrap v1.0.0 h1:6GlHJ/LTGMrIJbwgdqdl2eEH8o+Exx/0m8ir9Gns0u4= github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= +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/ioprogress v0.0.0-20180201004757-6a23b12fa88e/go.mod h1:waEya8ee1Ro/lgxpVhkJI4BVASzkm3UZqkx/cFJiYHM= -github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE= +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.3.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/osext v0.0.0-20151018003038-5e2d6d41470f/go.mod h1:OkQIRizQZAeMln+1tSwduZz7+Af5oFlKirV/MSYes2A= github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/moby/spdystream v0.2.0 h1:cjW1zVyyoiM0T7b6UoySUFqzXMoqRckQtXwGPiBhOM8= +github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c= +github.com/moby/term v0.0.0-20201216013528-df9cb8a40635 h1:rzf0wL0CHVc8CEsgyygG0Mn9CNCCPZqOPaz8RiiHYQk= +github.com/moby/term v0.0.0-20201216013528-df9cb8a40635/go.mod h1:FBS0z0QWA44HXygs7VXDUOGoN/1TV3RuWkLO04am3wc= 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= @@ -530,67 +897,93 @@ github.com/modern-go/reflect2 v0.0.0-20180320133207-05fbef0ca5da/go.mod h1:bx2lN 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/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8= +github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00/go.mod h1:Pm3mSP3c5uWn86xMLZ5Sa7JB9GsEZySvHYXCTK4E9q4= github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= +github.com/mozilla/tls-observatory v0.0.0-20190404164649-a3c1b6cfecfd/go.mod h1:SrKMQvPiws7F7iqYp8/TX+IhxCYhzr6N/1yb8cwHsGk= +github.com/mozilla/tls-observatory v0.0.0-20200317151703-4fa42e1c2dee/go.mod h1:SrKMQvPiws7F7iqYp8/TX+IhxCYhzr6N/1yb8cwHsGk= github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= 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/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= +github.com/nakabonne/nestif v0.3.0/go.mod h1:dI314BppzXjJ4HsCnbo7XzrJHPszZsjnk5wEBSYHI2c= +github.com/natefinch/lumberjack v2.0.0+incompatible/go.mod h1:Wi9p2TTF5DG5oU+6YfsmYQpsTIOm0B1VNzQg9Mw6nPk= +github.com/nats-io/gnatsd v1.4.1/go.mod h1:nqco77VO78hLCJpIcVfygDP2rPGfsEHkGTUk94uh5DQ= +github.com/nats-io/go-nats v1.7.0/go.mod h1:+t7RHT5ApZebkrQdnn6AhQJmhJJiKAvJUio1PiiCtj0= github.com/nats-io/jwt v0.3.0/go.mod h1:fRYCDE99xlTsqUzISS1Bi75UBJ6ljOJQOAAu5VglpSg= github.com/nats-io/jwt v0.3.2/go.mod h1:/euKqTS1ZD+zzjYrY7pseZrTtWQSjujC7xjPc8wL6eU= github.com/nats-io/nats-server/v2 v2.1.2/go.mod h1:Afk+wRZqkMQs/p45uXdrVLuab3gwv3Z8C4HTBu8GD/k= github.com/nats-io/nats.go v1.9.1/go.mod h1:ZjDU1L/7fJ09jvUSRVBR2e7+RnLiiIQyqyzEE/Zbp4w= +github.com/nats-io/nkeys v0.0.2/go.mod h1:dab7URMsZm6Z/jp9Z5UGa87Uutgc2mVpXLC4B7TDb/4= github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= github.com/nats-io/nkeys v0.1.3/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= +github.com/nats-io/nuid v1.0.0/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= github.com/nbio/st v0.0.0-20140626010706-e9e8d9816f32/go.mod h1:9wM+0iRr9ahx58uYLpLIr5fm8diHn0JbqRycJi6w0Ms= +github.com/nbutton23/zxcvbn-go v0.0.0-20180912185939-ae427f1e4c1d/go.mod h1:o96djdrsSGy3AWPyBgZMAGfxZNfgntdJG+11KU4QvbU= github.com/ncw/swift v1.0.47/go.mod h1:23YIA4yWVnGwv2dQlN4bB7egfYX6YLn0Yo/S6zZO/ZM= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/nwaples/rardecode v1.0.0/go.mod h1:5DzqNKiOdpKKBH87u8VlvAnPZMXcGRhxWkRpHbbfGS0= +github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= +github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= +github.com/octago/sflags v0.2.0/go.mod h1:G0bjdxh4qPRycF74a2B8pU36iTp9QHGx0w0dFZXPt80= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= -github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5 h1:58+kh9C6jJVXYjt8IE48G2eWl6BjwU5Gj0gqY84fy78= github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= -github.com/olekukonko/tablewriter v0.0.4 h1:vHD/YYe1Wolo78koG299f7V/VAS08c6IpCLn+Ejf/w8= github.com/olekukonko/tablewriter v0.0.4/go.mod h1:zq6QwlOf5SlnkVbMSr5EoBv3636FWnp+qbPhuoO21uA= github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.11.0 h1:JAKSXpt1YjtLA7YpPiqO9ss6sNXEsPfSGdwN0UHqzrw= +github.com/onsi/ginkgo v1.10.2/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.12.0/go.mod h1:oUhWkIvk5aDxtKvDDuw8gItl8pKl42LzjC9KZE0HfGg= +github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= +github.com/onsi/ginkgo v1.16.2/go.mod h1:CObGmKUOKaSC0RjmoAK7tKyn4Azo5P2IWuoMnvwxz1E= +github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= +github.com/onsi/gomega v0.0.0-20190113212917-5533ce8a0da3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/onsi/gomega v1.4.2/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= -github.com/onsi/gomega v1.8.1 h1:C5Dqfs/LeauYDX0jJXIe2SWmwCbGzx9yF8C8xy3Lh34= +github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.8.1/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA= +github.com/onsi/gomega v1.9.0/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA= +github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= +github.com/onsi/gomega v1.13.0/go.mod h1:lRk9szgn8TxENtWd0Tp4c3wjlRfMTMH27I+3Je41yGY= +github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk= github.com/opencontainers/go-digest v0.0.0-20170106003457-a6d0ee40d420/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= github.com/opencontainers/go-digest v0.0.0-20180430190053-c9281466c8b2/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= +github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.0.0/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= github.com/opencontainers/runc v0.0.0-20190115041553-12f6a991201f/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= github.com/opencontainers/runc v0.1.1/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= github.com/opencontainers/runtime-spec v0.1.2-0.20190507144316-5b71a03e2700/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= github.com/opencontainers/runtime-tools v0.0.0-20181011054405-1d69bd0f9c39/go.mod h1:r3f7wjNzSs2extwzU3Y+6pKfobzPh+kKFJ3ofN+3nfs= +github.com/openzipkin/zipkin-go v0.1.1/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8= github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw= github.com/openzipkin/zipkin-go v0.2.0/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4= -github.com/otiai10/copy v1.0.2 h1:DDNipYy6RkIkjMwy+AWzgKiNTyj2RUI9yEMeETEpVyc= +github.com/openzipkin/zipkin-go v0.2.2/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4= github.com/otiai10/copy v1.0.2/go.mod h1:c7RpqBkwMom4bYTSkLSym4VSJz/XtncWRAj/J4PEIMY= -github.com/otiai10/curr v0.0.0-20150429015615-9b4961190c95 h1:+OLn68pqasWca0z5ryit9KGfp3sUsW4Lqg32iRMJyzs= github.com/otiai10/curr v0.0.0-20150429015615-9b4961190c95/go.mod h1:9qAhocn7zKJG+0mI8eUu6xqkFDYS2kb2saOteoSB3cE= -github.com/otiai10/curr v1.0.0 h1:TJIWdbX0B+kpNagQrjgq8bCMrbhiuX73M2XwgtDMoOI= github.com/otiai10/curr v1.0.0/go.mod h1:LskTG5wDwr8Rs+nNQ+1LlxRjAtTZZjtJW4rMXl6j4vs= -github.com/otiai10/mint v1.3.0 h1:Ady6MKVezQwHBkGzLFbrsywyp09Ah7rkmfjV3Bcr5uc= 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/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= github.com/pelletier/go-buffruneio v0.2.0/go.mod h1:JkE26KsDizTr40EUHkXVtNPvgGtbSNq5BcowyYOWdKo= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= -github.com/pelletier/go-toml v1.6.0 h1:aetoXYr0Tv7xRU/V4B4IZJ2QcbtMUFoNb3ORp7TzIK4= +github.com/pelletier/go-toml v1.3.0/go.mod h1:PN7xzY2wHTK0K9p34ErDQMlFxa51Fk0OUruD3k1mMwo= github.com/pelletier/go-toml v1.6.0/go.mod h1:5N711Q9dKgbdkxHL+MEfF31hpT7l0S0s/t2kKREewys= +github.com/pelletier/go-toml v1.8.0/go.mod h1:D6yutnOGMveHEPV7VQOuvI/gXY61bv+9bAOTRnLElKs= github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= +github.com/phayes/checkstyle v0.0.0-20170904204023-bfd46e6a821d/go.mod h1:3OzsM7FXDQlpCiw2j81fOmAwQLnZnLGXVKUzeKQXIAw= github.com/phayes/freeport v0.0.0-20180830031419-95f893ade6f2/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE= github.com/pierrec/lz4 v0.0.0-20190327172049-315a67e90e41/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc= github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc= @@ -599,13 +992,17 @@ github.com/pierrec/lz4 v2.2.6+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1-0.20171018195549-f15c970de5b7/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/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA= github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 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/pquerna/cachecontrol v0.0.0-20171018203845-0dec1b30a021/go.mod h1:prYjPmNq4d1NPVmpShWobRqXY3q7Vp+80DqgxxUrUIA= github.com/prometheus/client_golang v0.0.0-20180209125602-c332b6f63c06/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v0.8.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v0.9.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v0.9.2/go.mod h1:OsXs2jCmiKlQ1lTBmv21f2mNfw4xf/QclQDMrYNZzcM= github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs= @@ -613,6 +1010,9 @@ github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDf github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQP1xR9D75/vuwEF3g= github.com/prometheus/client_golang v1.5.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= +github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= +github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= +github.com/prometheus/client_model v0.0.0-20170216185247-6f3806018612/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20171117100541-99fa1f4be8e5/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= @@ -620,6 +1020,9 @@ github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1: github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/common v0.0.0-20180110214958-89604d197083/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= +github.com/prometheus/common v0.0.0-20180518154759-7600349dcfe1/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= +github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= +github.com/prometheus/common v0.0.0-20181020173914-7e9e6cabbd39/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= github.com/prometheus/common v0.0.0-20181126121408-4724e9255275/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= @@ -628,7 +1031,11 @@ github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y8 github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc= github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA= github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= +github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= +github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= github.com/prometheus/procfs v0.0.0-20180125133057-cb4147076ac7/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.0-20180612222113-7d6f385de8be/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20181204211112-1dc9a6cbc91a/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= @@ -638,89 +1045,142 @@ github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDa github.com/prometheus/procfs v0.0.5/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ= github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= github.com/prometheus/procfs v0.0.10/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= +github.com/prometheus/procfs v0.0.11/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= +github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= +github.com/prometheus/procfs v0.2.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= +github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= -github.com/qiniu/api.v7/v7 v7.5.0 h1:DY6NrIp6FZ1GP4Roc9hRnO2m+OLzASYNnvz5Mbgw1rk= -github.com/qiniu/api.v7/v7 v7.5.0/go.mod h1:VE5oC5rkE1xul0u1S2N0b2Uxq9/6hZzhyqjgK25XDcM= +github.com/quasilyte/go-consistent v0.0.0-20190521200055-c6f3937de18c/go.mod h1:5STLWrekHfjyYwxBRVRXNOSewLJ3PWfDJd1VyTS21fI= +github.com/quasilyte/go-ruleguard v0.1.2-0.20200318202121-b00d7a75d3d8/go.mod h1:CGFX09Ci3pq9QZdj86B+VGIdNj4VyCo2iPOGS9esB/k= github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= github.com/rcrowley/go-metrics v0.0.0-20190706150252-9beb055b7962/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= github.com/remyoudompheng/bigfft v0.0.0-20170806203942-52369c62f446/go.mod h1:uYEyJGbgTkfkS4+E/PavXkNJcbFIpEtjt2B0KDQ5+9M= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= +github.com/rogpeppe/fastuuid v1.1.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= +github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= +github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.3.2/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= +github.com/rogpeppe/go-internal v1.5.2/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= github.com/rubiojr/go-vhd v0.0.0-20160810183302-0bfd3b39853c/go.mod h1:DM5xW0nvfNNm2uytzsvhI3OnX8uzaRAg8UX/CnDqbto= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/rwcarlsen/goexif v0.0.0-20190401172101-9e8deecbddbd/go.mod h1:hPqNNc0+uJM6H+SuU8sEs5K5IQeKccPqeSjfgcKGgPk= +github.com/ryancurrah/gomodguard v1.0.4/go.mod h1:9T/Cfuxs5StfsocWr4WzDL36HqnX0fVb9d5fSEaLhoE= +github.com/ryancurrah/gomodguard v1.1.0/go.mod h1:4O8tr7hBODaGE6VIhfJDHcwzh5GUccKSJBU0UMXJFVM= +github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/sassoftware/go-rpmutils v0.0.0-20190420191620-a8f1baeba37b/go.mod h1:am+Fp8Bt506lA3Rk3QCmSqmYmLMnPDhdDUcosQCAx+I= +github.com/satori/go.uuid v0.0.0-20160713180306-0aa62d5ddceb/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= github.com/sclevine/spec v1.2.0/go.mod h1:W4J29eT/Kzv7/b9IWLB055Z+qvVC9vt0Arko24q7p+U= +github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= +github.com/securego/gosec v0.0.0-20200103095621-79fbf3af8d83/go.mod h1:vvbZ2Ae7AzSq3/kywjUDxSNq2SJ27RxCz2un0H3ePqE= +github.com/securego/gosec v0.0.0-20200401082031-e946c8c39989/go.mod h1:i9l/TNj+yDFh9SZXUTvspXTjbFXgZGP/UvhU1S65A4A= +github.com/securego/gosec/v2 v2.3.0/go.mod h1:UzeVyUXbxukhLeHKV3VVqo7HdoQR9MrRfFmZYotn8ME= github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= +github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= +github.com/shirou/gopsutil v0.0.0-20190901111213-e4ec7b275ada/go.mod h1:WWnYX4lzhCH5h/3YBfyVA3VbLYjlMZZAQcW9ojMexNc= +github.com/shirou/w32 v0.0.0-20160930032740-bb4de0191aa4/go.mod h1:qsXQc7+bwAM3Q1u/4XEfrquwF8Lw7D7y5cD8CuHnfIc= +github.com/shurcooL/githubv4 v0.0.0-20180925043049-51d7b505e2e9/go.mod h1:hAF0iLZy4td2EX+/8Tw+4nodhlMrwN3HupfaXj3zkGo= github.com/shurcooL/githubv4 v0.0.0-20190718010115-4ba037080260/go.mod h1:hAF0iLZy4td2EX+/8Tw+4nodhlMrwN3HupfaXj3zkGo= github.com/shurcooL/githubv4 v0.0.0-20191102174205-af46314aec7b/go.mod h1:hAF0iLZy4td2EX+/8Tw+4nodhlMrwN3HupfaXj3zkGo= +github.com/shurcooL/go v0.0.0-20180423040247-9e1955d9fb6e/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk= +github.com/shurcooL/go-goon v0.0.0-20170922171312-37c2f522c041/go.mod h1:N5mDOmsrJOB+vfqUK+7DmDyjhSLIIBnXo9lvZJj3MWQ= +github.com/shurcooL/graphql v0.0.0-20180924043259-e4a3a37e6d42/go.mod h1:AuYgA5Kyo4c7HfUmvRGs/6rGlMMV/6B1bVnB9JxJEEg= github.com/shurcooL/graphql v0.0.0-20181231061246-d48a9a75455f/go.mod h1:AuYgA5Kyo4c7HfUmvRGs/6rGlMMV/6B1bVnB9JxJEEg= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/sirupsen/logrus v1.0.4-0.20170822132746-89742aefa4b2/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc= +github.com/sirupsen/logrus v1.0.5/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc= +github.com/sirupsen/logrus v1.1.1/go.mod h1:zrgwTnHtNr00buQ1vSptGe8m1f/BbgsPukg8qsT7A+A= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= -github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= -github.com/sirupsen/logrus v1.6.0 h1:UBcNElsrwanuuMsnGSlYmtmgbb23qDR5dG+6X6Oo89I= github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= -github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM= +github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/assertions v1.0.0/go.mod h1:kHHU4qYBaI3q23Pp3VPrmWhuIUrLW/7eUrw0BU5VaoM= +github.com/smartystreets/go-aws-auth v0.0.0-20180515143844-0c1422d1fdb9/go.mod h1:SnhjPscd9TpLiy1LpzGSKh3bXCfxxXuqd9xmQJy3slM= github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/smartystreets/goconvey v0.0.0-20190731233626-505e41936337/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= -github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= +github.com/smartystreets/gunit v1.0.0/go.mod h1:qwPWnhz6pn0NnRBP++URONOVyNkPyr4SauJk4cUOwJs= +github.com/soheilhy/cmux v0.1.3/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= +github.com/sourcegraph/go-diff v0.5.1/go.mod h1:j2dHj3m8aZgQO8lMTcTnBcXkRRRqi34cd2MNlA9u1mE= +github.com/sourcegraph/go-diff v0.5.3/go.mod h1:v9JDtjCE4HHHCZGId75rg8gkKKa98RVjBcBGsVmMmak= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= -github.com/spf13/afero v1.2.2 h1:5jhuqJyZCZf2JRofRvN/nIFgIWNzPa3/Vz8mYylgbWc= github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= -github.com/spf13/cast v1.3.1 h1:nFm6S0SMdyzrzcmThSipiEubIDy8WEXKNZ0UOgiRpng= github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cobra v0.0.0-20180319062004-c439c4fa0937/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/cobra v0.0.2-0.20171109065643-2da4a54c5cee/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= github.com/spf13/cobra v0.0.6/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= -github.com/spf13/cobra v1.0.0 h1:6m/oheQuQ13N9ks4hubMG6BnvwOeaJrqSPLahSnczz8= github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= +github.com/spf13/cobra v1.1.1/go.mod h1:WnodtKOvamDL/PwE2M4iKs8aMDBZ5Q5klgD3qfVJQMI= +github.com/spf13/cobra v1.1.3 h1:xghbfqPkxzxP3C/f3n5DdpAbdKLj4ZE4BWQI362l53M= +github.com/spf13/cobra v1.1.3/go.mod h1:pGADOWyqRD/YMrPZigI/zbliZ2wVD/23d+is3pSWzOo= github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= -github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.1-0.20171106142849-4c012f6dcd95/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= -github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg= +github.com/spf13/pflag v1.0.2/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= 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.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE= -github.com/spf13/viper v1.6.2 h1:7aKfF+e8/k68gda3LOjo5RxiUqddoFxVq4BKBPrxk5E= +github.com/spf13/viper v1.6.1/go.mod h1:t3iDnF5Jlj76alVNuyFBk5oUMCvsrkbvZK0WQdfDi5k= github.com/spf13/viper v1.6.2/go.mod h1:t3iDnF5Jlj76alVNuyFBk5oUMCvsrkbvZK0WQdfDi5k= +github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= github.com/src-d/gcfg v1.4.0/go.mod h1:p/UMsR43ujA89BJY9duynAwIpvqEujIH/jFlfL7jWoI= +github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8= github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= +github.com/streadway/quantile v0.0.0-20150917103942-b0c588724d25/go.mod h1:lbP8tGiBjZ5YWIc2fzuRpTaz0b/53vT6PEs3QuAWzuU= 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/objx v0.2.0 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48= github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= github.com/stretchr/testify v0.0.0-20151208002404-e3a8ff8ce365/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 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= -github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s= +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/syndtr/gocapability v0.0.0-20170704070218-db04d3cc01c8/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= +github.com/tdakkota/asciicheck v0.0.0-20200416190851-d7f85be797a2/go.mod h1:yHp0ai0Z9gUljN3o0xMhYJnH/IcvkdTBOX2fmJ93JEM= +github.com/tdakkota/asciicheck v0.0.0-20200416200610-e657995f937b/go.mod h1:yHp0ai0Z9gUljN3o0xMhYJnH/IcvkdTBOX2fmJ93JEM= +github.com/tektoncd/pipeline v0.8.0/go.mod h1:IZzJdiX9EqEMuUcgdnElozdYYRh0/ZRC+NKMLj1K3Yw= +github.com/tektoncd/pipeline v0.10.1/go.mod h1:D2X0exT46zYx95BU7ByM8+erpjoN7thmUBvlKThOszU= github.com/tektoncd/pipeline v0.11.0/go.mod h1:hlkH32S92+/UODROH0dmxzyuMxfRFp/Nc3e29MewLn8= +github.com/tektoncd/pipeline v0.13.1-0.20200625065359-44f22a067b75/go.mod h1:R5AlT46x/F8n/pFJFjZ1U1q71GWtVXgG7RZkkoRL554= +github.com/tektoncd/plumbing v0.0.0-20191216083742-847dcf196de9/go.mod h1:QZHgU07PRBTRF6N57w4+ApRu8OgfYLFNqCDlfEZaD9Y= github.com/tektoncd/plumbing v0.0.0-20200217163359-cd0db6e567d2/go.mod h1:QZHgU07PRBTRF6N57w4+ApRu8OgfYLFNqCDlfEZaD9Y= +github.com/tektoncd/plumbing v0.0.0-20200430135134-e53521e1d887/go.mod h1:cZPJIeTIoP7UPTxQyTQLs7VE1TiXJSNj0te+If4Q+jI= github.com/tektoncd/plumbing/pipelinerun-logs v0.0.0-20191206114338-712d544c2c21/go.mod h1:S62EUWtqmejjJgUMOGB1CCCHRp6C706laH06BoALkzU= +github.com/tetafro/godot v0.3.7/go.mod h1:/7NLHhv08H1+8DNj0MElpAACw1ajsCuf3TKNQxA5S+0= +github.com/tetafro/godot v0.4.2/go.mod h1:/7NLHhv08H1+8DNj0MElpAACw1ajsCuf3TKNQxA5S+0= github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= +github.com/timakin/bodyclose v0.0.0-20190930140734-f7f2e9bca95e/go.mod h1:Qimiffbc6q9tBWlVV6x0P9sat/ao1xEkREYPPj9hphk= +github.com/timakin/bodyclose v0.0.0-20200424151742-cb6215831a94/go.mod h1:Qimiffbc6q9tBWlVV6x0P9sat/ao1xEkREYPPj9hphk= +github.com/tj/assert v0.0.0-20171129193455-018094318fb0/go.mod h1:mZ9/Rh9oLWpLLDRpvE+3b7gP/C2YyLFYxNmcLnPTMe0= +github.com/tj/go-elastic v0.0.0-20171221160941-36157cbbebc2/go.mod h1:WjeM0Oo1eNAjXGDx2yma7uG2XoyRZTq1uv3M/o7imD0= +github.com/tj/go-kinesis v0.0.0-20171128231115-08b17f58cb1b/go.mod h1:/yhzCV0xPfx6jb1bBgRFjl5lytqVqZXEaeqWP8lTEao= +github.com/tj/go-spin v1.1.0/go.mod h1:Mg1mzmePZm4dva8Qz60H2lHwmJ2loum4VIrLgVnKwh4= github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= +github.com/tommy-muehle/go-mnd v1.1.1/go.mod h1:dSUh0FtTP8VhvkL1S+gUR1OKd9ZnSaozuI6r3m6wOig= +github.com/tommy-muehle/go-mnd v1.3.1-0.20200224220436-e6f9a994e8fa/go.mod h1:dSUh0FtTP8VhvkL1S+gUR1OKd9ZnSaozuI6r3m6wOig= github.com/tongjingran/copy v1.4.2 h1:faPaod07yG6Z+o1B52Vu1KTvRb8il5VDNKLprC1BmsE= github.com/tongjingran/copy v1.4.2/go.mod h1:Njma1OR5OuzB8pLAmQSzonHXzba+DDiPVmMSonpSpy4= +github.com/trivago/tgo v1.0.1/go.mod h1:w4dpD+3tzNIIiIfkWWa85w5/B77tlvdZckQ+6PkFnhc= +github.com/tsenart/vegeta v12.7.1-0.20190725001342-b5f4fca92137+incompatible/go.mod h1:Smz/ZWfhKRcyDDChZkG3CyTHdj87lHzio/HOCkbndXM= +github.com/ugorji/go v1.1.1/go.mod h1:hnLbHMwcvSihnDhEfx2/BzKp2xb0Y+ErdfYcrs9tkJQ= github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo= github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= @@ -728,13 +1188,24 @@ github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljT github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs= github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= github.com/ulikunitz/xz v0.5.6/go.mod h1:2bypXElzHzzJZwzH67Y6wb67pO62Rzfn7BSiF4ABRW8= +github.com/ulikunitz/xz v0.5.7/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= +github.com/ultraware/funlen v0.0.2/go.mod h1:Dp4UiAus7Wdb9KUZsYWZEWiRzGuM2kXM1lPbfaF6xhA= +github.com/ultraware/whitespace v0.0.4/go.mod h1:aVMh/gQve5Maj9hQ/hg+F75lr/X5A89uZnzAmWSineA= github.com/urfave/cli v0.0.0-20171014202726-7bc6a0acffa5/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= +github.com/urfave/cli v1.18.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= +github.com/uudashr/gocognit v1.0.1/go.mod h1:j44Ayx2KW4+oB6SWMv8KsmHzZrOInQav7D3cQMJ5JUM= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= +github.com/valyala/fasthttp v1.2.0/go.mod h1:4vX61m6KN+xDduDNwXrhIAVZaZaZiQ1luJk8LWSxF3s= +github.com/valyala/quicktemplate v1.2.0/go.mod h1:EH+4AkTd43SvgIbQHYu59/cJyxDoOVRUAfrukLPuGJ4= +github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio= github.com/vdemeester/k8s-pkg-credentialprovider v0.0.0-20200107171650-7c61ffa44238/go.mod h1:JwQJCMWpUDqjZrB5jpw0f5VbN7U95zxFy1ZDpoEarGo= github.com/vdemeester/k8s-pkg-credentialprovider v1.13.12-1/go.mod h1:Fko0rTxEtDW2kju5Ky7yFJNS3IcNvW8IPsp4/e9oev0= +github.com/vdemeester/k8s-pkg-credentialprovider v1.17.4/go.mod h1:inCTmtUdr5KJbreVojo06krnTgaeAz/Z7lynpPk/Q2c= github.com/vektah/gqlparser v1.1.2/go.mod h1:1ycwN7Ij5njmMkPPAOaRFY4rET2Enx7IkVv3vaXspKw= github.com/vmware/govmomi v0.20.3/go.mod h1:URlwyTFZX72RmxtxuaFL2Uj3fD1JTvZdx59bHWk6aFU= +github.com/xanzy/go-gitlab v0.31.0/go.mod h1:sPLojNBn68fMUWSxIJtdVVIP8uSBYqesTfDUseX11Ug= +github.com/xanzy/go-gitlab v0.32.0/go.mod h1:sPLojNBn68fMUWSxIJtdVVIP8uSBYqesTfDUseX11Ug= github.com/xanzy/ssh-agent v0.2.1/go.mod h1:mLlQY/MoOhWBj+gOGMQkOeiEvkx+8pJSI+0Bx9h2kr4= github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c/go.mod h1:lB8K/P019DLNhemzwFU4jHLhdvlE6uDZjXFejJXr49I= github.com/xdg/stringprep v1.0.0/go.mod h1:Jhud4/sHMO4oL310DaZAKk9ZaJ08SJfe+sJh0HrGL1Y= @@ -743,20 +1214,31 @@ github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1: github.com/xeipuuv/gojsonschema v0.0.0-20180618132009-1d523034197f/go.mod h1:5yf86TLmAcydyeJq5YvxkGPE2fm/u4myDekKRoLuqhs= github.com/xeipuuv/gojsonschema v1.1.0/go.mod h1:5yf86TLmAcydyeJq5YvxkGPE2fm/u4myDekKRoLuqhs= github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8/go.mod h1:HUYIGzjTL3rfEspMxjDjgmT5uz5wzYJKVo23qUhYTos= +github.com/xiang90/probing v0.0.0-20160813154853-07dd2e8dfe18/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xlab/handysort v0.0.0-20150421192137-fb3537ed64a1/go.mod h1:QcJo0QPSfTONNIgpN5RA8prR7fF8nkF6cTWTcNerRO8= +github.com/xlab/treeprint v0.0.0-20181112141820-a009c3971eca/go.mod h1:ce1O1j6UtZfjr22oyGxGLbauSBp2YVXpARAosm7dHBg= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= +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= github.com/yvasiyarov/go-metrics v0.0.0-20140926110328-57bccd1ccd43/go.mod h1:aX5oPXxHm3bOH+xeAttToC8pqch2ScQN/JoXYupl6xs= github.com/yvasiyarov/gorelic v0.0.0-20141212073537-a9bba5b9ab50/go.mod h1:NUSPSUX/bi6SeDMUh6brw0nXpxHnc96TguQh0+r/ssA= github.com/yvasiyarov/newrelic_platform_go v0.0.0-20140908184405-b21fdbd4370f/go.mod h1:GlGEuHIJweS1mbCqG+7vt2nvWLzLLnRHbXz5JKd/Qbg= +go.etcd.io/bbolt v1.3.1-etcd.7/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= +go.etcd.io/bbolt v1.3.5/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ= +go.etcd.io/etcd v0.0.0-20181031231232-83304cfc808c/go.mod h1:weASp41xM3dk0YHg1s/W8ecdGP5G4teSTMBPpYAaUgA= go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg= +go.etcd.io/etcd v0.5.0-alpha.5.0.20200910180754-dd1b699fc489/go.mod h1:yVHk9ub3CSBatqGNg7GRmsnfLWtoW60w4eDYfh7vHDg= go.mongodb.org/mongo-driver v1.0.3/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM= go.mongodb.org/mongo-driver v1.1.1/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM= go.mongodb.org/mongo-driver v1.1.2/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM= go.opencensus.io v0.15.0/go.mod h1:UffZAU+4sDEINUGP/B7UfBBkq4fqLu9zXAX7ke6CHW0= +go.opencensus.io v0.17.0/go.mod h1:mp1VrMQxhlqqDpKvH4UcQUa4YwlzNmymAjPrDdfxNpI= go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= @@ -764,22 +1246,42 @@ go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.1/go.mod h1:Ap50jQcDJrx6rB6VgeeFPtuPIf3wMRvRfrfYDO6+BmA= 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.starlark.net v0.0.0-20200306205701-8dd3e2ee1dd5/go.mod h1:nmDLcffg48OtT/PSW0Hg7FvpRQsQh5OSqIylirxKC7o= +go.uber.org/atomic v0.0.0-20181018215023-8dc6146f7569/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= go.uber.org/atomic v1.5.1/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= +go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw= +go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= +go.uber.org/multierr v0.0.0-20180122172545-ddea229ff1df/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= go.uber.org/multierr v1.4.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= +go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4= +go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= +go.uber.org/zap v0.0.0-20180814183419-67bc79d13d15/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= +go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= +go.uber.org/zap v1.9.2-0.20180814183419-67bc79d13d15/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= go.uber.org/zap v1.14.1/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc= +go.uber.org/zap v1.15.0/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc= +go.uber.org/zap v1.17.0 h1:MTjgFu6ZLKvY6Pvaqk97GlxNBuMpV4Hy/3P6tRGlI2U= +go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo= +go4.org v0.0.0-20201209231011-d4a079459e60/go.mod h1:CIiUVy99QCPfoE13bO4EZaz5GZMZXMSBGhxRdsvzbkg= gocloud.dev v0.19.0/go.mod h1:SmKwiR8YwIMMJvQBKLsC3fHNyMwXLw3PMDO+VVteJMI= golang.org/x/crypto v0.0.0-20171113213409-9f005a07e0d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20180608092829-8ac0e0d97ce4/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181015023909-0c41d7ab0a0e/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181025213731-e84da0312774/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190219172222-a4c6cb3142f2/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= @@ -787,6 +1289,7 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk golang.org/x/crypto v0.0.0-20190320223903-b7391e95e576/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190404164418-38d8ce5564a5/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= +golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= @@ -794,13 +1297,21 @@ golang.org/x/crypto v0.0.0-20190617133340-57b3e21c3d56/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190911031432-227b76d455e7/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191002192127-34f69633bfdc/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191117063200-497ca9f6d64f/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20191205180655-e7c4368fe9dd/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200128174031-69ecbb4d6d5d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073 h1:xMPOj6Pz6UipU1wXLkrtqpHbR0AVFnyPEQq/wRWz9lM= +golang.org/x/crypto v0.0.0-20200220183623-bac4c82f6975/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83 h1:/ZScEX8SfEmUGRHs0gxpqteO5nfNW6axyZbBdw9A12g= +golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= +golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -809,8 +1320,15 @@ golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxT golang.org/x/exp v0.0.0-20190731235908-ec7cb31e5a56/go.mod h1:JhuoJpWY28nO4Vef9tZUw9qufEGTyX1+7lmHxV5q5G4= golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= golang.org/x/exp v0.0.0-20191002040644-a1355ae1e2c3/go.mod h1:NOZ3BPKG0ec/BKJQgnvsSFpcKLM5xXVWnvZS97DWHgE= +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-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= 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= @@ -820,7 +1338,6 @@ golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHl 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 h1:Wh+f8QHJXR411sJR8/vRBTZ7YapZaRvUcLFFJhusH0k= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/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= @@ -828,14 +1345,20 @@ golang.org/x/mobile v0.0.0-20190806162312-597adff16ade/go.mod h1:AlhUtkH4DA4asiF 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 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.3.1-0.20200828183125-ce943fd02449/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-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 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-20180911220305-26e67e76b6c3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181005035420-146acd28ed58/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-20181108082009-03003ca0c849/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-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -854,39 +1377,72 @@ golang.org/x/net v0.0.0-20190619014844-b5b0513f8c1b/go.mod h1:z5CRVTTTmAJ677TzLL 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-20190812203447-cdfb69ac37fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190912160710-24e19bdeb0f2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191002035440-2ec189313ef0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191004110552-13f9640d40b9/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191112182307-2180aed22343/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191119073136-fc4aabc6c914/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 h1:GuSPYbZzB5/dcLNCwLQLsg3obCJtX9IJhpXkvY7kzk0= golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200625001655-4c5254603344 h1:vGXIOMxbNfDTk/aXCmfdLgkrSV+Z2tcbze+pEc3v5W4= +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-20200904194848-62affa334b73/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-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20210224082022-3d97a244fca7/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +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-20180724155351-3d292e4d0cdc/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20181106182150-f42d05182288/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-20190402181905-9f3314589c9a/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d h1:TzXSXBo42m9gQenoE3b9BGiEpg5IG2JkU5FkPIawgtw= +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 h1:ld7aEMNHoBnnDAX15v1T6z31v8HwR2A9FYOuAhWqkwc= +golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/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-20170830134202-bb24a47a89ea/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +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-20181107165924-66b7b1311ac8/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-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190209173611-3b5209105503/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-20190219203350-90b0e4468f99/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190221075227-b4e8571b14e0/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= @@ -903,83 +1459,204 @@ golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190620070143-6f217b454f45/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190712062909-fae7ac547cb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190804053845-51ab0e2deafa/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190912141932-bc967efca4b8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191002063906-3421d5a6bb1c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191010194322-b09406accb47/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191022100944-742c48ecaeb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191112214154-59a1497f0cea/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191119060738-e882bf8e40c2/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-20191210023423-ac6580df4449/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-20200302150141-5c8b2ff67527 h1:uYVVQ9WP/Ds2ROhcaGPeIdVq0RIXVLwsHlnvJ+cT1So= +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 h1:xhmwyvizuTgC2qz7ZlMluP20uW+C3Rm0FD/WLDX8884= +golang.org/x/sys v0.0.0-20200317113312-5766fd39f98d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200327173247-9dae0f8f5775/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-20200610111108-226ff32320da/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-20200828194041-157a740278f4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200831180312-196b9ba8737a/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-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-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210426230700-d19ff857e887/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-20210608053332-aa57babbf139 h1:C+AwYEtBp/VQwoLntUmQ/yx3MS9vmZaKNdw5eOpoQe8= +golang.org/x/sys v0.0.0-20210608053332-aa57babbf139/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d h1:SZxvLBoTP5yHO3Frd4z4vrF+DBX9vMVanchswa69toE= +golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +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 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= +golang.org/x/text v0.3.1-0.20181227161524-e6919f6577db/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= 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.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= 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/time v0.0.0-20200416051211-89c76fbcd5d1/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba h1:O8mE0/t419eoIwhTFpKVkHiTs/Igowgfkj25AcZrtiE= +golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20181011042414-1f849cf54d09/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20181117154741-2ddaf7f79a09/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190110163146-51295c7ec13a/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-20190125232054-d66bd3c5d5a6/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190206041539-40960b6deb8e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190221204921-83362c3779f5/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= -golang.org/x/tools v0.0.0-20190311212946-11955173bddd h1:/e+gpKk9r3dJobndpTytxS2gOy6m5uvpg+ISQoEcusQ= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190311215038-5c2858a9cfe5/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-20190322203728-c1a832b0ad89/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190422233926-fe54fb35175b/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-20190521203540-521d6ed310dd/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-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190617190820-da514acc4774/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-20190624222133-a101b041ded4/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-20190706070813-72ffa07ba3db/go.mod h1:jcCCGcm9btYwXyDqrUWc6MKQKKGJCWEQ3AfLSRIbEuI= +golang.org/x/tools v0.0.0-20190719005602-e377ae9d6386/go.mod h1:jcCCGcm9btYwXyDqrUWc6MKQKKGJCWEQ3AfLSRIbEuI= golang.org/x/tools v0.0.0-20190729092621-ff9f1409240a/go.mod h1:jcCCGcm9btYwXyDqrUWc6MKQKKGJCWEQ3AfLSRIbEuI= golang.org/x/tools v0.0.0-20190807223507-b346f7fd45de/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190910044552-dd2b5c81c578/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-20190920225731-5eefd052ad72/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190927191325-030b2cf1153e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191010075000-0337d82405ff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191010171213-8abd42400456/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-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191112005509-a3f652f18032/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-20191113232020-e2727e816f5a/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-20191118222007-07fc4c7f2b98/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-20200102140908-9497f49d5709/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200115165105-de0b1760071a/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-20200204192400-7124308813f3/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-20200210192313-1ace956b0e17/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-20200214144324-88be01311a71/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200303214625-2b0b585e22fe h1:Kh3iY7o/2bMfQXZdwLdL9jDMU1k9HoVn0P1mGCfoFLc= +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-20200303214625-2b0b585e22fe/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= -golang.org/x/tools v0.0.0-20200730221956-1ac65761fe2c h1:c5JjBOQWM2pRemVbog00sS+oAdi8tTR+NNRFDwUOrTQ= -golang.org/x/tools v0.0.0-20200730221956-1ac65761fe2c/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +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-20200317043434-63da46f3035e/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= +golang.org/x/tools v0.0.0-20200324003944-a576cf524670/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= +golang.org/x/tools v0.0.0-20200329025819-fd4102a86c65/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= +golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= +golang.org/x/tools v0.0.0-20200331202046-9d5940d49312/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200414032229-332987a829c3/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200422022333-3d57cf2e726e/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200426102838-f3a5411a4c3b/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200502202811-ed308ab3e770/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200505023115-26f46d2f7ef8/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-20200527183253-8e7acdbce89d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200601175630-2caf76543d99/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-20200626171337-aa94e735be7f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200701000337-a32c0cb1d5b2/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-20200828161849-5deb26317202/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= +golang.org/x/tools v0.0.0-20200915173823-2db8f0ff891c/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU= +golang.org/x/tools v0.0.0-20200918232735-d647fc253266/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU= +golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/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.3 h1:L69ShwSZEyCsLKoAxDKeMvLDZkumEe8gXUZAjab0tX8= +golang.org/x/tools v0.1.3/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 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= 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= gomodules.xyz/jsonpatch/v2 v2.0.1/go.mod h1:IhYNNY4jnS53ZnfE4PAmpKtDpTCj1JFXc+3mwe7XcUU= gomodules.xyz/jsonpatch/v2 v2.1.0/go.mod h1:IhYNNY4jnS53ZnfE4PAmpKtDpTCj1JFXc+3mwe7XcUU= +gomodules.xyz/jsonpatch/v2 v2.2.0/go.mod h1:WXp+iVDkoLQqPudfQ9GBlwB2eZ5DKOnjQZCYdOS8GPY= +gonum.org/v1/gonum v0.0.0-20181121035319-3f7ecaa7e8ca/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo= gonum.org/v1/gonum v0.0.0-20190331200053-3d26580ed485/go.mod h1:2ltnJ7xHfj0zHS40VVPYEAAMTa3ZGguvHGBSJeRWqE0= +gonum.org/v1/netlib v0.0.0-20181029234149-ec6d1f5cefe6/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= gonum.org/v1/netlib v0.0.0-20190331212654-76723241ea4e/go.mod h1:kS+toOQn6AQKjmKJ7gzohV1XkqsFehRA2FbsbkopSuQ= google.golang.org/api v0.0.0-20160322025152-9bf6e6e569ff/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= +google.golang.org/api v0.0.0-20180910000450-7ca32eb868bf/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= +google.golang.org/api v0.0.0-20181021000519-a2651947f503/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= google.golang.org/api v0.5.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= @@ -989,16 +1666,39 @@ google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E 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.10.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.25.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.26.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.31.0/go.mod h1:CL+9IBCa2WWU6gRuBWaKqGWLFFwbEUXkfeMkHLQWYWo= +google.golang.org/api v0.32.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= 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.2/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= -google.golang.org/appengine v1.6.5 h1:tycE03LOZYQNhDpS27tcQdAzLCVMaj7QT2SXxebnpCM= 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 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= +google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/cloud v0.0.0-20151119220103-975617b05ea8/go.mod h1:0H1ncTHf11KCFhTc/+EFRbzSCOZx+VUbRMk55Yv5MYk= +google.golang.org/genproto v0.0.0-20170731182057-09f6ed296fc6/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20180608181217-32ee49c4dd80/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20181016170114-94acd270e44e/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= @@ -1011,8 +1711,47 @@ google.golang.org/genproto v0.0.0-20190716160619-c506a9f90610/go.mod h1:DMBHOl98 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-20190927181202-20e1ac93f88c/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= google.golang.org/genproto v0.0.0-20191009194640-548a555dbc03/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +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-20200317114155-1f3552e48f24/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200326112834-f447254575fd/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-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-20200527145253-8367513e4ece/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= +google.golang.org/genproto v0.0.0-20200528110217-3d3490e7e671/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= +google.golang.org/genproto v0.0.0-20200603110839-e855014d5736/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= +google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= +google.golang.org/genproto v0.0.0-20200626011028-ee7919e894b5/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200701001935-0939c5918c31/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +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-20200804151602-45615f50871c/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-20200831141814-d751682dd103/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-20200914193844-75d14daec038/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200921151605-7abf4a1a14d5/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201019141844-1ed22bb0c154/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201110150050-8816d57aaa9a/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/grpc v0.0.0-20160317175043-d3ddb4469d5a/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= +google.golang.org/grpc v1.13.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= +google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= +google.golang.org/grpc v1.15.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio= google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.19.1/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= @@ -1020,56 +1759,94 @@ google.golang.org/grpc v1.20.0/go.mod h1:chYK+tFQF0nDUGJgXMSgLCQk3phJEuONr2DCgLD google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/grpc v1.22.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.22.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.24.0/go.mod h1:XDChyiUovWa60DnaeDeZmSW86xtLtjtZbwvSiRnRtcA= +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.32.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +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/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U= 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-20141024133853-64131543e789/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.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/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= -gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/gcfg.v1 v1.2.0/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o= gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2/go.mod h1:Xk6kEKp8OKb+X14hQBKWaSkCsqBpgog8nAV2xsGOxlo= gopkg.in/inf.v0 v0.9.0/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= +gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/ini.v1 v1.46.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= -gopkg.in/ini.v1 v1.52.0 h1:j+Lt/M1oPPejkniCg1TkWE2J3Eh1oZTsHSXzMTzUXn4= gopkg.in/ini.v1 v1.52.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/ini.v1 v1.56.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/jcmturner/aescts.v1 v1.0.1/go.mod h1:nsR8qBOg+OucoIW+WMhB3GspUQXq9XorLnQb9XtvcOo= gopkg.in/jcmturner/dnsutils.v1 v1.0.1/go.mod h1:m3v+5svpVOhtFAP/wSz+yzh4Mc0Fg7eRhxkJMWSIz9Q= gopkg.in/jcmturner/gokrb5.v7 v7.2.3/go.mod h1:l8VISx+WGYp+Fp7KRbsiUuXTTOnxIc3Tuvyavf11/WM= gopkg.in/jcmturner/gokrb5.v7 v7.3.0/go.mod h1:l8VISx+WGYp+Fp7KRbsiUuXTTOnxIc3Tuvyavf11/WM= gopkg.in/jcmturner/rpc.v1 v1.1.0/go.mod h1:YIdkC4XfD6GXbzje11McwsDuOlZQSb9W4vfLvuNnlv8= +gopkg.in/natefinch/lumberjack.v2 v2.0.0-20150622162204-20b71e5b60d7/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= gopkg.in/robfig/cron.v2 v2.0.0-20150107220207-be2e0b0deed5/go.mod h1:hiOFpYm0ZJbusNj2ywpbrXowU3G8U6GIQzqn2mw1UIE= +gopkg.in/square/go-jose.v2 v2.0.0-20180411045311-89060dee6a84/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= gopkg.in/square/go-jose.v2 v2.2.2/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= gopkg.in/src-d/go-billy.v4 v4.3.2/go.mod h1:nDjArDMp+XMs1aFAESLRjfGSgfvoYN0hDfzEk0GjC98= gopkg.in/src-d/go-git-fixtures.v3 v3.5.0/go.mod h1:dLBcvytrw/TYZsNTWCnkNF2DSIlzWYqTe3rJR56Ac7g= gopkg.in/src-d/go-git.v4 v4.13.1/go.mod h1:nx5NYcxdKxq5fpltdHnPa2Exj4Sx0EclMWZQbYDu2z8= -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/warnings.v0 v0.1.1/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= +gopkg.in/yaml.v1 v1.0.0-20140924161607-9f9df34309c0/go.mod h1:WDnlLJ4WF5VGsH/HVa3CI79GS0ol3YnhVnKP89i0kNg= gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= 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 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= +gopkg.in/yaml.v2 v2.2.7/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-20190709130402-674ba3eaed22/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/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= +gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo= gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= +gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk= +gotest.tools/v3 v3.0.3 h1:4AuOwCGf4lLR9u3YOe2awrHygurzhO/HeQ6laiA6Sx0= +gotest.tools/v3 v3.0.3/go.mod h1:Z7Lb0S5l+klDB31fvDQX8ss/FlKDxtlFlw3Oa8Ymbl8= helm.sh/helm/v3 v3.1.1/go.mod h1:WYsFJuMASa/4XUqLyv54s0U/f3mlAaRErGmyy4z921g= honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= @@ -1078,66 +1855,197 @@ honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.1-2019.2.2/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= 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= +k8s.io/api v0.0.0-20180904230853-4e7be11eab3f/go.mod h1:iuAfoD4hCxJ8Onx9kaTIt30j7jUFS00AXQi6QMi99vA= +k8s.io/api v0.0.0-20181018013834-843ad2d9b9ae/go.mod h1:iuAfoD4hCxJ8Onx9kaTIt30j7jUFS00AXQi6QMi99vA= +k8s.io/api v0.0.0-20190918195907-bd6ac527cfd2/go.mod h1:AOxZTnaXR/xiarlQL0JUfwQPxjmKDvVYoRp58cA7lUo= +k8s.io/api v0.16.4/go.mod h1:AtzMnsR45tccQss5q8RnF+W8L81DH6XwXwo/joEx9u0= +k8s.io/api v0.16.13/go.mod h1:QWu8UWSTiuQZMMeYjwLs6ILu5O74qKSJ0c+4vrchDxs= k8s.io/api v0.17.0/go.mod h1:npsyOePkeP0CPwyGfXDHxvypiYMJxBWAMpQxCaJ4ZxI= k8s.io/api v0.17.2/go.mod h1:BS9fjjLc4CMuqfSO8vgbHPKMt5+SF0ET6u/RVDihTo4= k8s.io/api v0.17.3/go.mod h1:YZ0OTkuw7ipbe305fMpIdf3GLXZKRigjtZaV5gzC2J0= +k8s.io/api v0.17.4/go.mod h1:5qxx6vjmwUVG2nHQTKGlLts8Tbok8PzHl4vHtVFuZCA= +k8s.io/api v0.17.6/go.mod h1:1jKVwkj0UZ4huak/yRt3MFfU5wc32+B41SkNN5HhyFg= +k8s.io/api v0.21.1/go.mod h1:FstGROTmsSHBarKc8bylzXih8BLNYTiS3TZcsoEDg2s= +k8s.io/api v0.21.2 h1:vz7DqmRsXTCSa6pNxXwQ1IYeAZgdIsua+DZU+o+SX3Y= +k8s.io/api v0.21.2/go.mod h1:Lv6UGJZ1rlMI1qusN8ruAp9PUBFyBwpEHAdG24vIsiU= +k8s.io/apiextensions-apiserver v0.0.0-20190918201827-3de75813f604/go.mod h1:7H8sjDlWQu89yWB3FhZfsLyRCRLuoXoCoY5qtwW1q6I= +k8s.io/apiextensions-apiserver v0.16.4/go.mod h1:HYQwjujEkXmQNhap2C9YDdIVOSskGZ3et0Mvjcyjbto= k8s.io/apiextensions-apiserver v0.17.2/go.mod h1:4KdMpjkEjjDI2pPfBA15OscyNldHWdBCfsWMDWAmSTs= +k8s.io/apiextensions-apiserver v0.17.6/go.mod h1:Z3CHLP3Tha+Rbav7JR3S+ye427UaJkHBomK2c4XtZ3A= +k8s.io/apiextensions-apiserver v0.21.1/go.mod h1:KESQFCGjqVcVsZ9g0xX5bacMjyX5emuWcS2arzdEouA= +k8s.io/apimachinery v0.0.0-20180904193909-def12e63c512/go.mod h1:ccL7Eh7zubPUSh9A3USN90/OzHNSVN6zxzde07TDCL0= +k8s.io/apimachinery v0.0.0-20181015213631-60666be32c5d/go.mod h1:ccL7Eh7zubPUSh9A3USN90/OzHNSVN6zxzde07TDCL0= k8s.io/apimachinery v0.0.0-20190703205208-4cfb76a8bf76/go.mod h1:M2fZgZL9DbLfeJaPBCDqSqNsdsmLN+V29knYJnIXlMA= +k8s.io/apimachinery v0.0.0-20190816221834-a9f1d8a9c101/go.mod h1:ccL7Eh7zubPUSh9A3USN90/OzHNSVN6zxzde07TDCL0= +k8s.io/apimachinery v0.0.0-20190817020851-f2f3a405f61d/go.mod h1:3jediapYqJ2w1BFw7lAZPCx7scubsTfosqHkhXCWJKw= +k8s.io/apimachinery v0.16.4/go.mod h1:llRdnznGEAqC3DcNm6yEj472xaFVfLM7hnYofMb12tQ= +k8s.io/apimachinery v0.16.5-beta.1/go.mod h1:llRdnznGEAqC3DcNm6yEj472xaFVfLM7hnYofMb12tQ= +k8s.io/apimachinery v0.16.13/go.mod h1:4HMHS3mDHtVttspuuhrJ1GGr/0S9B6iWYWZ57KnnZqQ= k8s.io/apimachinery v0.17.0/go.mod h1:b9qmWdKlLuU9EBh+06BtLcSf/Mu89rWL33naRxs1uZg= +k8s.io/apimachinery v0.17.1/go.mod h1:b9qmWdKlLuU9EBh+06BtLcSf/Mu89rWL33naRxs1uZg= k8s.io/apimachinery v0.17.2/go.mod h1:b9qmWdKlLuU9EBh+06BtLcSf/Mu89rWL33naRxs1uZg= -k8s.io/apimachinery v0.17.3 h1:f+uZV6rm4/tHE7xXgLyToprg6xWairaClGVkm2t8omg= k8s.io/apimachinery v0.17.3/go.mod h1:gxLnyZcGNdZTCLnq3fgzyg2A5BVCHTNDFrw8AmuJ+0g= +k8s.io/apimachinery v0.17.4/go.mod h1:gxLnyZcGNdZTCLnq3fgzyg2A5BVCHTNDFrw8AmuJ+0g= +k8s.io/apimachinery v0.17.6/go.mod h1:Lg8zZ5iC/O8UjCqW6DNhcQG2m4TdjF9kwG3891OWbbA= +k8s.io/apimachinery v0.18.5/go.mod h1:OaXp26zu/5J7p0f92ASynJa1pZo06YlV9fG7BoWbCko= +k8s.io/apimachinery v0.21.1/go.mod h1:jbreFvJo3ov9rj7eWT7+sYiRx+qZuCYXwWT1bcDswPY= +k8s.io/apimachinery v0.21.2 h1:vezUc/BHqWlQDnZ+XkrpXSmnANSLbpnlpwo0Lhk0gpc= +k8s.io/apimachinery v0.21.2/go.mod h1:CdTY8fU/BlvAbJ2z/8kBwimGki5Zp8/fbVuLY8gJumM= +k8s.io/apiserver v0.0.0-20190918200908-1e17798da8c1/go.mod h1:4FuDU+iKPjdsdQSN3GsEKZLB/feQsj1y9dhhBDVV2Ns= +k8s.io/apiserver v0.16.4/go.mod h1:kbLJOak655g6W7C+muqu1F76u9wnEycfKMqbVaXIdAc= k8s.io/apiserver v0.17.0/go.mod h1:ABM+9x/prjINN6iiffRVNCBR2Wk7uY4z+EtEGZD48cg= k8s.io/apiserver v0.17.2/go.mod h1:lBmw/TtQdtxvrTk0e2cgtOxHizXI+d0mmGQURIHQZlo= +k8s.io/apiserver v0.17.4/go.mod h1:5ZDQ6Xr5MNBxyi3iUZXS84QOhZl+W7Oq2us/29c0j9I= +k8s.io/apiserver v0.17.6/go.mod h1:sAYqm8hUDNA9aj/TzqwsJoExWrxprKv0tqs/z88qym0= +k8s.io/apiserver v0.21.1/go.mod h1:nLLYZvMWn35glJ4/FZRhzLG/3MPxAaZTgV4FJZdr+tY= k8s.io/cli-runtime v0.17.2/go.mod h1:aa8t9ziyQdbkuizkNLAw3qe3srSyWh9zlSB7zTqRNPI= k8s.io/cli-runtime v0.17.3/go.mod h1:X7idckYphH4SZflgNpOOViSxetiMj6xI0viMAjM81TA= -k8s.io/client-go v0.17.0/go.mod h1:TYgR6EUHs6k45hb6KWjVD6jFZvJV4gHDikv/It0xz+k= -k8s.io/client-go v0.17.2/go.mod h1:QAzRgsa0C2xl4/eVpeVAZMvikCn8Nm81yqVx3Kk9XYI= -k8s.io/client-go v0.17.3/go.mod h1:cLXlTMtWHkuK4tD360KpWz2gG2KtdWEr/OT02i3emRQ= -k8s.io/client-go v9.0.0+incompatible/go.mod h1:7vJpHMYJwNQCWgzmNV+VYUl1zCObLyodBc8nIyt8L5s= +k8s.io/cli-runtime v0.21.2/go.mod h1:8u/jFcM0QpoI28f6sfrAAIslLCXUYKD5SsPPMWiHYrI= +k8s.io/client-go v0.21.1 h1:bhblWYLZKUu+pm50plvQF8WpY6TXdRRtcS/K9WauOj4= +k8s.io/client-go v0.21.1/go.mod h1:/kEw4RgW+3xnBGzvp9IWxKSNA+lXn3A7AuH3gdOAzLs= k8s.io/cloud-provider v0.17.0/go.mod h1:Ze4c3w2C0bRsjkBUoHpFi+qWe3ob1wI2/7cUn+YQIDE= +k8s.io/cloud-provider v0.17.4/go.mod h1:XEjKDzfD+b9MTLXQFlDGkk6Ho8SGMpaU8Uugx/KNK9U= +k8s.io/code-generator v0.0.0-20190612205613-18da4a14b22b/go.mod h1:G8bQwmHm2eafm5bgtX67XDZQ8CWKSGu9DekI+yN4Y5I= +k8s.io/code-generator v0.0.0-20190831074504-732c9ca86353/go.mod h1:V5BD6M4CyaN5m+VthcclXWsVcT1Hu+glwa1bi3MIsyE= +k8s.io/code-generator v0.16.4/go.mod h1:mJUgkl06XV4kstAnLHAIzJPVCOzVR+ZcfPIv4fUsFCY= k8s.io/code-generator v0.17.1/go.mod h1:DVmfPQgxQENqDIzVR2ddLXMH34qeszkKSdH/N+s+38s= k8s.io/code-generator v0.17.2/go.mod h1:DVmfPQgxQENqDIzVR2ddLXMH34qeszkKSdH/N+s+38s= k8s.io/code-generator v0.17.3/go.mod h1:l8BLVwASXQZTo2xamW5mQNFCe1XPiAesVq7Y1t7PiQQ= +k8s.io/code-generator v0.17.6/go.mod h1:iiHz51+oTx+Z9D0vB3CH3O4HDDPWrvZyUgUYaIE9h9M= +k8s.io/code-generator v0.18.0/go.mod h1:+UHX5rSbxmR8kzS+FAv7um6dtYrZokQvjHpDSYRVkTc= +k8s.io/code-generator v0.21.1/go.mod h1:hUlps5+9QaTrKx+jiM4rmq7YmH8wPOIko64uZCHDh6Q= +k8s.io/code-generator v0.21.2/go.mod h1:8mXJDCB7HcRo1xiEQstcguZkbxZaqeUOrO9SsicWs3U= +k8s.io/component-base v0.0.0-20190918200425-ed2f0867c778/go.mod h1:DFWQCXgXVLiWtzFaS17KxHdlUeUymP7FLxZSkmL9/jU= +k8s.io/component-base v0.16.4/go.mod h1:GYQ+4hlkEwdlpAp59Ztc4gYuFhdoZqiAJD1unYDJ3FM= k8s.io/component-base v0.17.0/go.mod h1:rKuRAokNMY2nn2A6LP/MiwpoaMRHpfRnrPaUJJj1Yoc= k8s.io/component-base v0.17.2/go.mod h1:zMPW3g5aH7cHJpKYQ/ZsGMcgbsA/VyhEugF3QT1awLs= +k8s.io/component-base v0.17.4/go.mod h1:5BRqHMbbQPm2kKu35v3G+CpVq4K0RJKC7TRioF0I9lE= +k8s.io/component-base v0.17.6/go.mod h1:jgRLWl0B0rOzFNtxQ9E4BphPmDqoMafujdau6AdG2Xo= +k8s.io/component-base v0.21.1/go.mod h1:NgzFZ2qu4m1juby4TnrmpR8adRk6ka62YdH5DkIIyKA= +k8s.io/component-base v0.21.2/go.mod h1:9lvmIThzdlrJj5Hp8Z/TOgIkdfsNARQ1pT+3PByuiuc= +k8s.io/component-helpers v0.21.2/go.mod h1:DbyFt/A0p6Cv+R5+QOGSJ5f5t4xDfI8Yb89a57DgJlQ= k8s.io/csi-translation-lib v0.17.0/go.mod h1:HEF7MEz7pOLJCnxabi45IPkhSsE/KmxPQksuCrHKWls= +k8s.io/csi-translation-lib v0.17.4/go.mod h1:CsxmjwxEI0tTNMzffIAcgR9lX4wOh6AKHdxQrT7L0oo= +k8s.io/gengo v0.0.0-20190116091435-f8a0810f38af/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= k8s.io/gengo v0.0.0-20190128074634-0689ccc1d7d6/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= +k8s.io/gengo v0.0.0-20190306031000-7a1b7fb0289f/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= k8s.io/gengo v0.0.0-20190822140433-26a664648505/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= k8s.io/gengo v0.0.0-20191108084044-e500ee069b5c/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= +k8s.io/gengo v0.0.0-20200114144118-36b2048a9120/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= +k8s.io/gengo v0.0.0-20200205140755-e0e292d8aa12/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= +k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= +k8s.io/gengo v0.0.0-20201214224949-b6c5ce23f027/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E= k8s.io/klog v0.0.0-20181102134211-b9b56d5dfc92/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= k8s.io/klog v0.3.0/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= k8s.io/klog v0.3.1/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= +k8s.io/klog v0.3.3/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= +k8s.io/klog v0.4.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I= k8s.io/klog v1.0.0 h1:Pt+yjF5aB1xDSVbau4VsWe+dQNzA0qv1LlXdC2dF6Q8= k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I= +k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE= +k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= +k8s.io/klog/v2 v2.8.0 h1:Q3gmuM9hKEjefWFFYF0Mat+YyFJvsUyYuwyNNJ5C9Ts= +k8s.io/klog/v2 v2.8.0/go.mod h1:hy9LJ/NvuK+iVyP4Ehqva4HxZG/oXyIS3n3Jmire4Ec= +k8s.io/kube-openapi v0.0.0-20180731170545-e3762e86a74c/go.mod h1:BXM9ceUBTj2QnfH2MK1odQs778ajze1RxcmP6S8RVVc= k8s.io/kube-openapi v0.0.0-20190228160746-b3a7cee44a30/go.mod h1:BXM9ceUBTj2QnfH2MK1odQs778ajze1RxcmP6S8RVVc= +k8s.io/kube-openapi v0.0.0-20190816220812-743ec37842bf/go.mod h1:1TqjTSzOxsLGIKfj0lK8EeCP7K1iUG65v09OM0/WG5E= k8s.io/kube-openapi v0.0.0-20191107075043-30be4d16710a/go.mod h1:1TqjTSzOxsLGIKfj0lK8EeCP7K1iUG65v09OM0/WG5E= +k8s.io/kube-openapi v0.0.0-20200121204235-bf4fb3bd569c/go.mod h1:GRQhZsXIAJ1xR0C9bd8UpWHZ5plfAS9fzPjJuQ6JL3E= +k8s.io/kube-openapi v0.0.0-20200410145947-61e04a5be9a6/go.mod h1:GRQhZsXIAJ1xR0C9bd8UpWHZ5plfAS9fzPjJuQ6JL3E= +k8s.io/kube-openapi v0.0.0-20200410145947-bcb3869e6f29/go.mod h1:F+5wygcW0wmRTnM3cOgIqGivxkwSWIWT5YdsDbeAOaU= +k8s.io/kube-openapi v0.0.0-20200410163147-594e756bea31/go.mod h1:1TqjTSzOxsLGIKfj0lK8EeCP7K1iUG65v09OM0/WG5E= +k8s.io/kube-openapi v0.0.0-20210305001622-591a79e4bda7/go.mod h1:wXW5VT87nVfh/iLV8FpR2uDvrFyomxbtb1KivDbvPTE= k8s.io/kubectl v0.17.2/go.mod h1:y4rfLV0n6aPmvbRCqZQjvOp3ezxsFgpqL+zF5jH/lxk= -k8s.io/kubernetes v1.13.0 h1:qTfB+u5M92k2fCCCVP2iuhgwwSOv1EkAkvQY1tQODD8= +k8s.io/kubectl v0.21.2 h1:9XPCetvOMDqrIZZXb1Ei+g8t6KrIp9ENJaysQjUuLiE= +k8s.io/kubectl v0.21.2/go.mod h1:PgeUclpG8VVmmQIl8zpLar3IQEpFc9mrmvlwY3CK1xo= +k8s.io/kubernetes v1.11.10/go.mod h1:ocZa8+6APFNC2tX1DZASIbocyYT5jHzqFVsY5aoB7Jk= k8s.io/kubernetes v1.13.0/go.mod h1:ocZa8+6APFNC2tX1DZASIbocyYT5jHzqFVsY5aoB7Jk= +k8s.io/kubernetes v1.14.7/go.mod h1:ocZa8+6APFNC2tX1DZASIbocyYT5jHzqFVsY5aoB7Jk= k8s.io/legacy-cloud-providers v0.17.0/go.mod h1:DdzaepJ3RtRy+e5YhNtrCYwlgyK87j/5+Yfp0L9Syp8= +k8s.io/legacy-cloud-providers v0.17.4/go.mod h1:FikRNoD64ECjkxO36gkDgJeiQWwyZTuBkhu+yxOc1Js= k8s.io/metrics v0.17.2/go.mod h1:3TkNHET4ROd+NfzNxkjoVfQ0Ob4iZnaHmSEA4vYpwLw= -k8s.io/test-infra v0.0.0-20200511080351-8ac9dbfab055 h1:tdigZYWTCLlgNqogEip0dS2hF7bdxnobwuwX73mmXQk= -k8s.io/test-infra v0.0.0-20200511080351-8ac9dbfab055/go.mod h1:bW6thaPZfL2hW7ecjx2WYwlP9KQLM47/xIJyttkVk5s= +k8s.io/metrics v0.21.2/go.mod h1:wzlOINZMCtWq8dR9gHlyaOemmYlOpAoldEIXE82gAhI= +k8s.io/test-infra v0.0.0-20181019233642-2e10a0bbe9b3/go.mod h1:2NzXB13Ji0nqpyublHeiPC4FZwU0TknfvyaaNfl/BTA= +k8s.io/test-infra v0.0.0-20191212060232-70b0b49fe247/go.mod h1:d8SKryJBXAwfCFVL4wieRez47J2NOOAb9d029sWLseQ= +k8s.io/test-infra v0.0.0-20200407001919-bc7f71ef65b8/go.mod h1:/WpJWcaDvuykB322WXP4kJbX8IpalOzuPxA62GpwkJk= +k8s.io/test-infra v0.0.0-20200514184223-ba32c8aae783/go.mod h1:bW6thaPZfL2hW7ecjx2WYwlP9KQLM47/xIJyttkVk5s= +k8s.io/test-infra v0.0.0-20200617221206-ea73eaeab7ff/go.mod h1:L3+cRvwftUq8IW1TrHji5m3msnc4uck/7LsE/GR/aZk= +k8s.io/test-infra v0.0.0-20200630233406-1dca6122872e/go.mod h1:L3+cRvwftUq8IW1TrHji5m3msnc4uck/7LsE/GR/aZk= +k8s.io/test-infra v0.0.0-20210618100605-34aa2f2aa75b h1:AOWfAJMFgx03P6gkDVgJPU8FYTRIJ/mAK/3lM2AguF8= +k8s.io/test-infra v0.0.0-20210618100605-34aa2f2aa75b/go.mod h1:QPyq1EhIX/9jcDa3dt6wtMFPC1TAYjAex8PMrNahE5Y= +k8s.io/utils v0.0.0-20181019225348-5e321f9a457c/go.mod h1:8k8uAuAQ0rXslZKaEWd0c3oVhZz7sSzSiPnVZayjIX0= +k8s.io/utils v0.0.0-20190221042446-c2654d5206da/go.mod h1:8k8uAuAQ0rXslZKaEWd0c3oVhZz7sSzSiPnVZayjIX0= +k8s.io/utils v0.0.0-20190506122338-8fab8cb257d5/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew= +k8s.io/utils v0.0.0-20190801114015-581e00157fb1/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew= +k8s.io/utils v0.0.0-20190907131718-3d4f5b7dea0b/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew= k8s.io/utils v0.0.0-20191114184206-e782cd3c129f/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew= +k8s.io/utils v0.0.0-20200124190032-861946025e34/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew= +k8s.io/utils v0.0.0-20201110183641-67b214c5f920/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= +k8s.io/utils v0.0.0-20210527160623-6fdb442a123b h1:MSqsVQ3pZvPGTqCjptfimO2WjG7A9un2zcpiHkA6M/s= +k8s.io/utils v0.0.0-20210527160623-6fdb442a123b/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= +knative.dev/caching v0.0.0-20190719140829-2032732871ff/go.mod h1:dHXFU6CGlLlbzaWc32g80cR92iuBSpsslDNBWI8C7eg= knative.dev/caching v0.0.0-20200116200605-67bca2c83dfa/go.mod h1:dHXFU6CGlLlbzaWc32g80cR92iuBSpsslDNBWI8C7eg= +knative.dev/eventing-contrib v0.6.1-0.20190723221543-5ce18048c08b/go.mod h1:SnXZgSGgMSMLNFTwTnpaOH7hXDzTFtw0J8OmHflNx3g= knative.dev/eventing-contrib v0.11.2/go.mod h1:SnXZgSGgMSMLNFTwTnpaOH7hXDzTFtw0J8OmHflNx3g= +knative.dev/pkg v0.0.0-20191101194912-56c2594e4f11/go.mod h1:pgODObA1dTyhNoFxPZTTjNWfx6F0aKsKzn+vaT9XO/Q= +knative.dev/pkg v0.0.0-20191111150521-6d806b998379/go.mod h1:pgODObA1dTyhNoFxPZTTjNWfx6F0aKsKzn+vaT9XO/Q= knative.dev/pkg v0.0.0-20200207155214-fef852970f43/go.mod h1:pgODObA1dTyhNoFxPZTTjNWfx6F0aKsKzn+vaT9XO/Q= +knative.dev/pkg v0.0.0-20200428194351-90fc61bae7f7/go.mod h1:o+e8OVEJKIuvXPsGVPIautjXgs05xbos7G+QMRjuUps= +knative.dev/pkg v0.0.0-20200505191044-3da93ebb24c2/go.mod h1:Q6sL35DdGs8hIQZKdaCXJGgY8f90BmNBKSb8z6d/BTM= +knative.dev/pkg v0.0.0-20200515002500-16d7b963416f/go.mod h1:tMOHGbxtRz8zYFGEGpV/bpoTEM1o89MwYFC4YJXl3GY= +knative.dev/pkg v0.0.0-20200528142800-1c6815d7e4c9/go.mod h1:QgNZTxnwpB/oSpNcfnLVlw+WpEwwyKAvJlvR3hgeltA= +knative.dev/pkg v0.0.0-20200711004937-22502028e31a/go.mod h1:AqAJV6rYi8IGikDjJ/9ZQd9qKdkXVlesVnVjwx62YB8= +knative.dev/test-infra v0.0.0-20200407185800-1b88cb3b45a5/go.mod h1:xcdUkMJrLlBswIZqL5zCuBFOC22WIPMQoVX1L35i0vQ= +knative.dev/test-infra v0.0.0-20200505052144-5ea2f705bb55/go.mod h1:WqF1Azka+FxPZ20keR2zCNtiQA1MP9ZB4BH4HuI+SIU= +knative.dev/test-infra v0.0.0-20200513011557-d03429a76034/go.mod h1:aMif0KXL4g19YCYwsy4Ocjjz5xgPlseYV+B95Oo4JGE= +knative.dev/test-infra v0.0.0-20200519015156-82551620b0a9/go.mod h1:A5b2OAXTOeHT3hHhVQm3dmtbuWvIDP7qzgtqxA3/2pE= +knative.dev/test-infra v0.0.0-20200707183444-aed09e56ddc7/go.mod h1:RjYAhXnZqeHw9+B0zsbqSPlae0lCvjekO/nw5ZMpLCs= modernc.org/cc v1.0.0/go.mod h1:1Sk4//wdnYJiUIxnW8ddKpaOJCF37yAdqYnkxUpaYxw= modernc.org/golex v1.0.0/go.mod h1:b/QX9oBD/LhixY6NDh+IdGv17hgB+51fET1i2kPSmvk= modernc.org/mathutil v1.0.0/go.mod h1:wU0vUrJsVWBZ4P6e7xtFJEhFSNsfRLJ8H458uRjg03k= modernc.org/strutil v1.0.0/go.mod h1:lstksw84oURvj9y3tn8lGvRxyRC1S2+g5uuIzNfIOBs= modernc.org/xc v1.0.0/go.mod h1:mRNCo0bvLjGhHO9WsyuKVU4q0ceiDDDoEeWDJHrNx8I= +mvdan.cc/interfacer v0.0.0-20180901003855-c20040233aed/go.mod h1:Xkxe497xwlCKkIaQYRfC7CSLworTXY9RMqwhhCm+8Nc= +mvdan.cc/lint v0.0.0-20170908181259-adc824a0674b/go.mod h1:2odslEg/xrtNQqCYg2/jCoyKnw3vv5biOc3JnIcYfL4= +mvdan.cc/unparam v0.0.0-20190720180237-d51796306d8f/go.mod h1:4G1h5nDURzA3bwVMZIVpwbkw+04kSxk3rAtzlimaUJw= +mvdan.cc/unparam v0.0.0-20200501210554-b37ab49443f7/go.mod h1:HGC5lll35J70Y5v7vCGb9oLhHoScFwkHDJm/05RdSTc= mvdan.cc/xurls/v2 v2.0.0/go.mod h1:2/webFPYOXN9jp/lzuj0zuAVlF+9g4KPFJANH1oJhRU= pack.ag/amqp v0.11.0/go.mod h1:4/cbmt4EJXSKlG6LCfWHoqmN0uFdy5i/+YFz+fTfhV4= pack.ag/amqp v0.11.2/go.mod h1:4/cbmt4EJXSKlG6LCfWHoqmN0uFdy5i/+YFz+fTfhV4= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/letsencrypt v0.0.3/go.mod h1:buyQKZ6IXrRnB7TdkHP0RyEybLx18HHyOSoTyoOLqNY= +rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= +rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= +sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.15/go.mod h1:LEScyzhFmoF5pso/YSeBstl57mOzx9xlU9n85RGrDQg= +sigs.k8s.io/boskos v0.0.0-20200526191642-45fc818e2d00/go.mod h1:L1ubP7d1CCMSQSjKiZv6dGbh7b4kfoG+dFPj8cfYDnI= +sigs.k8s.io/boskos v0.0.0-20200617235605-f289ba6555ba/go.mod h1:ZO5RV+VxJS9mb6DvZ1yAjywoyq/wQ8b0vDoZxcIA5kE= +sigs.k8s.io/controller-runtime v0.3.0/go.mod h1:Cw6PkEg0Sa7dAYovGT4R0tRkGhHXpYijwNxYhAnAZZk= sigs.k8s.io/controller-runtime v0.5.0/go.mod h1:REiJzC7Y00U+2YkMbT8wxgrsX5USpXKGhb2sCtAXiT8= +sigs.k8s.io/controller-runtime v0.5.4/go.mod h1:JZUwSMVbxDupo0lTJSSFP5pimEyxGynROImSsqIOx1A= +sigs.k8s.io/controller-runtime v0.9.0/go.mod h1:TgkfvrhhEw3PlI0BRL/5xM+89y3/yc0ZDfdbTl84si8= sigs.k8s.io/kustomize v2.0.3+incompatible/go.mod h1:MkjgH3RdOWrievjo6c9T245dYlB5QeXV4WCbnt/PEpU= +sigs.k8s.io/kustomize/api v0.8.8/go.mod h1:He1zoK0nk43Pc6NlV085xDXDXTNprtcyKZVm3swsdNY= +sigs.k8s.io/kustomize/cmd/config v0.9.10/go.mod h1:Mrby0WnRH7hA6OwOYnYpfpiY0WJIMgYrEDfwOeFdMK0= +sigs.k8s.io/kustomize/kustomize/v4 v4.1.2/go.mod h1:PxBvo4WGYlCLeRPL+ziT64wBXqbgfcalOS/SXa/tcyo= +sigs.k8s.io/kustomize/kyaml v0.10.17/go.mod h1:mlQFagmkm1P+W4lZJbJ/yaxMd8PqMRSC4cPcfUVt5Hg= +sigs.k8s.io/structured-merge-diff v0.0.0-20190302045857-e85c7b244fd2/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI= sigs.k8s.io/structured-merge-diff v0.0.0-20190525122527-15d366b2352e/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI= sigs.k8s.io/structured-merge-diff v1.0.1-0.20191108220359-b1b620dd3f06/go.mod h1:/ULNhyfzRopfcjskuui0cTITekDduZ7ycKN3oUT9R18= +sigs.k8s.io/structured-merge-diff v1.0.1 h1:LOs1LZWMsz1xs77Phr/pkB4LFaavH7IVq/3+WTN9XTA= +sigs.k8s.io/structured-merge-diff v1.0.1/go.mod h1:IIgPezJWb76P0hotTxzDbWsMYB8APh18qZnxkomBpxA= +sigs.k8s.io/structured-merge-diff/v2 v2.0.1/go.mod h1:Wb7vfKAodbKgf6tn1Kl0VvGj7mRH6DGaRcixXEJXTsE= +sigs.k8s.io/structured-merge-diff/v3 v3.0.0-20200116222232-67a7b8c61874/go.mod h1:PlARxl6Hbt/+BC80dRLi1qAmnMqwqDg62YvvVkZjemw= +sigs.k8s.io/structured-merge-diff/v3 v3.0.0/go.mod h1:PlARxl6Hbt/+BC80dRLi1qAmnMqwqDg62YvvVkZjemw= +sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= +sigs.k8s.io/structured-merge-diff/v4 v4.1.0 h1:C4r9BgJ98vrKnnVCjwCSXcWjWe0NKcUQkmzDXZXGwH8= +sigs.k8s.io/structured-merge-diff/v4 v4.1.0/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= +sigs.k8s.io/testing_frameworks v0.1.1/go.mod h1:VVBKrHmJ6Ekkfz284YKhQePcdycOzNH9qL6ht1zEr/U= sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= +sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q= sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= +sourcegraph.com/sqs/pbtypes v0.0.0-20180604144634-d3ebe8f20ae4/go.mod h1:ketZ/q3QxT9HOBeFhu6RdvsftgpsbFHBF5Cas6cDKZ0= +sourcegraph.com/sqs/pbtypes v1.0.0/go.mod h1:3AciMUv4qUuRHRHhOG4TZOB+72GdPVz5k+c648qsFS4= vbom.ml/util v0.0.0-20160121211510-db5cfe13f5cc/go.mod h1:so/NYdZXCz+E3ZpW0uAoCj6uzU2+8OWDFv/HxUSs7kI= vbom.ml/util v0.0.0-20180919145318-efcd4e0f9787/go.mod h1:so/NYdZXCz+E3ZpW0uAoCj6uzU2+8OWDFv/HxUSs7kI= diff --git a/goc.go b/main.go similarity index 93% rename from goc.go rename to main.go index 4ffade7..4b511ac 100644 --- a/goc.go +++ b/main.go @@ -1,12 +1,9 @@ /* Copyright 2020 Qiniu Cloud (qiniu.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. @@ -16,7 +13,9 @@ package main -import "github.com/qiniu/goc/cmd" +import ( + "github.com/qiniu/goc/v2/cmd" +) func main() { cmd.Execute() diff --git a/pkg/build/build.go b/pkg/build/build.go index 4fcbe40..f421978 100644 --- a/pkg/build/build.go +++ b/pkg/build/build.go @@ -1,168 +1,93 @@ -/* - Copyright 2020 Qiniu Cloud (qiniu.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" "os" "os/exec" - "path/filepath" - "strings" - "github.com/qiniu/goc/pkg/cover" - log "github.com/sirupsen/logrus" + "github.com/qiniu/goc/v2/pkg/config" + "github.com/qiniu/goc/v2/pkg/cover" + "github.com/qiniu/goc/v2/pkg/flag" + "github.com/qiniu/goc/v2/pkg/log" + "github.com/spf13/cobra" ) -// Build is to describe the building/installing process of a goc build/install +// Build struct a build +// most configurations are stored in global variables: config.GocConfig & config.GoConfig type Build struct { - Pkgs map[string]*cover.Package // Pkg list parsed from "go list -json ./..." command - NewGOPATH string // the new GOPATH - OriGOPATH string // the original GOPATH - WorkingDir string // the working directory - TmpDir string // the temporary directory to build the project - TmpWorkingDir string // the working directory in the temporary directory, which is corresponding to the current directory in the project directory - IsMod bool // determine whether it is a Mod project - Root string - // go 1.11, go 1.12 has no Root - // Project Root: - // 1. legacy, root == GOPATH - // 2. mod, root == go.mod Dir - ModRoot string // path for go.mod - ModRootPath string // import path for the whole project - Target string // the binary name that go build generate - // keep compatible with go commands: - // go run [build flags] [-exec xprog] package [arguments...] - // go build [-o output] [-i] [build flags] [packages] - // go install [-i] [build flags] [packages] - BuildFlags string // Build flags - Packages string // Packages that needs to build - GoRunExecFlag string // for the -exec flags in go run command - GoRunArguments string // for the '[arguments]' parameters in go run command - - OneMainPackage bool // whether this build is a go build or go install? true: build, false: install - GlobalCoverVarImportPath string // Importpath for storing cover variables - GlobalCoverVarFilePath string // Importpath for storing cover variables } -// NewBuild creates a Build struct which can build from goc temporary directory, -// and generate binary in current working directory -func NewBuild(buildflags string, args []string, workingDir string, outputDir string) (*Build, error) { - if err := checkParameters(args, workingDir); err != nil { - return nil, err - } - // buildflags = buildflags + " -o " + outputDir - b := &Build{ - BuildFlags: buildflags, - Packages: strings.Join(args, " "), - WorkingDir: workingDir, - } - if false == b.validatePackageForBuild() { - log.Errorln(ErrWrongPackageTypeForBuild) - return nil, ErrWrongPackageTypeForBuild - } - if err := b.MvProjectsToTmp(); err != nil { - return nil, err - } - dir, err := b.determineOutputDir(outputDir) - b.Target = dir - if err != nil { - return nil, err - } - return b, nil +// NewBuild creates a Build struct +// +// consumes args, get package dirs, read project meta info. +func NewBuild(cmd *cobra.Command, args []string) *Build { + b := &Build{} + // 1. 解析 goc 命令行和 go 命令行 + remainedArgs := flag.BuildCmdArgsParse(cmd, args) + // 2. 解析 go 包位置 + flag.GetPackagesDir(remainedArgs) + // 3. 读取工程元信息:go.mod, pkgs list ... + b.readProjectMetaInfo() + // 4. 展示元信息 + b.displayProjectMetaInfo() + + return b } -// Build calls 'go build' tool to do building -func (b *Build) Build() error { - log.Infoln("Go building in temp...") - // new -o will overwrite previous ones - b.BuildFlags = b.BuildFlags + " -o " + b.Target - cmd := exec.Command("/bin/bash", "-c", "go build "+b.BuildFlags+" "+b.Packages) - cmd.Dir = b.TmpWorkingDir +// Build starts go build +// +// 1. copy project to temp, +// 2. inject cover variables and functions into the project, +// 3. build the project in temp. +func (b *Build) Build() { + // 1. 拷贝至临时目录 + b.copyProjectToTmp() + defer b.clean() + + log.Donef("project copied to temporary directory") + // 2. inject cover vars + cover.Inject() + // 3. build in the temp project + b.doBuildInTemp() +} + +func (b *Build) doBuildInTemp() { + log.StartWait("building the injected project") + + goflags := config.GocConfig.Goflags + // 检查用户是否自定义了 -o + oSet := false + for _, flag := range goflags { + if flag == "-o" { + oSet = true + } + } + + // 如果没被设置就加一个至原命令执行的目录 + if !oSet { + goflags = append(goflags, "-o", config.GocConfig.CurWd) + } + + pacakges := config.GocConfig.Packages + + goflags = append(goflags, pacakges...) + + args := []string{"build"} + args = append(args, goflags...) + // go 命令行由 go build [-o output] [build flags] [packages] 组成 + cmd := exec.Command("go", args...) + cmd.Dir = config.GocConfig.TmpWd cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr - if b.NewGOPATH != "" { - // Change to temp GOPATH for go install command - cmd.Env = append(os.Environ(), fmt.Sprintf("GOPATH=%v", b.NewGOPATH)) + log.Infof("go build cmd is: %v, in path [%v]", cmd.Args, cmd.Dir) + if err := cmd.Start(); err != nil { + log.Fatalf("fail to execute go build: %v", err) + } + if err := cmd.Wait(); err != nil { + log.Fatalf("fail to execute go build: %v", err) } - log.Printf("go build cmd is: %v", cmd.Args) - err := cmd.Start() - if err != nil { - return fmt.Errorf("fail to execute: %v, err: %w", cmd.Args, err) - } - if err = cmd.Wait(); err != nil { - return fmt.Errorf("fail to execute: %v, err: %w", cmd.Args, err) - } - log.Infoln("Go build exit successful.") - return nil -} - -// determineOutputDir, as we only allow . as package name, -// the binary name is always same as the directory name of current directory -func (b *Build) determineOutputDir(outputDir string) (string, error) { - if b.TmpDir == "" { - return "", fmt.Errorf("can only be called after Build.MvProjectsToTmp(): %w", ErrEmptyTempWorkingDir) - } - - // fix #43 - if outputDir != "" { - abs, err := filepath.Abs(outputDir) - if err != nil { - return "", fmt.Errorf("Fail to transform the path: %v to absolute path: %v", outputDir, err) - - } - return abs, nil - } - // fix #43 - // use target name from `go list -json ./...` of the main module - targetName := "" - for _, pkg := range b.Pkgs { - if pkg.Name == "main" { - if pkg.Target != "" { - targetName = filepath.Base(pkg.Target) - } else { - targetName = filepath.Base(pkg.Dir) - } - break - } - } - - return filepath.Join(b.WorkingDir, targetName), nil -} - -// validatePackageForBuild only allow . as package name -func (b *Build) validatePackageForBuild() bool { - if b.Packages == "." || b.Packages == "" { - return true - } - return false -} - -func checkParameters(args []string, workingDir string) error { - if len(args) > 1 { - log.Errorln(ErrTooManyArgs) - return ErrTooManyArgs - } - - if workingDir == "" { - return ErrInvalidWorkingDir - } - - log.Infof("Working directory: %v", workingDir) - return nil + // done + log.StopWait() + log.Donef("go build done") } diff --git a/pkg/build/build_test.go b/pkg/build/build_test.go deleted file mode 100644 index 3237277..0000000 --- a/pkg/build/build_test.go +++ /dev/null @@ -1,101 +0,0 @@ -/* - Copyright 2020 Qiniu Cloud (qiniu.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 ( - "errors" - "fmt" - "os" - "path/filepath" - "testing" - - "github.com/stretchr/testify/assert" -) - -func TestInvalidPackage(t *testing.T) { - - workingDir := filepath.Join(baseDir, "../../tests/samples/simple_project") - gopath := "" - - os.Setenv("GOPATH", gopath) - os.Setenv("GO111MODULE", "on") - - _, err := NewBuild("", []string{"example.com/simple-project"}, workingDir, "") - if !assert.Equal(t, err, ErrWrongPackageTypeForBuild) { - assert.FailNow(t, "the package name should be invalid") - } -} - -func TestBasicBuildForModProject(t *testing.T) { - workingDir := filepath.Join(baseDir, "../../tests/samples/simple_project") - gopath := "" - - os.Setenv("GOPATH", gopath) - os.Setenv("GO111MODULE", "on") - fmt.Println(workingDir) - buildFlags, args, buildOutput := "", []string{"."}, "" - gocBuild, err := NewBuild(buildFlags, args, workingDir, buildOutput) - if !assert.Equal(t, err, nil) { - assert.FailNow(t, "should create temporary directory successfully") - } - - err = gocBuild.Build() - if !assert.Equal(t, err, nil) { - assert.FailNow(t, "temporary directory should build successfully") - } -} - -func TestCheckParameters(t *testing.T) { - err := checkParameters([]string{"aa", "bb"}, "aa") - assert.Equal(t, err, ErrTooManyArgs, "too many arguments should failed") - - err = checkParameters([]string{"aa"}, "") - assert.Equal(t, err, ErrInvalidWorkingDir, "empty working directory should failed") -} - -func TestDetermineOutputDir(t *testing.T) { - b := &Build{} - _, err := b.determineOutputDir("") - assert.Equal(t, errors.Is(err, ErrEmptyTempWorkingDir), true, "called before Build.MvProjectsToTmp() should fail") - - b.TmpDir = "fake" - _, err = b.determineOutputDir("xx") - assert.Equal(t, err, nil, "should return a directory") -} - -func TestInvalidPackageNameForBuild(t *testing.T) { - workingDir := filepath.Join(baseDir, "../../tests/samples/simple_project") - gopath := filepath.Join(baseDir, "../../tests/samples/simple_project", "testhome") - - os.Setenv("GOPATH", gopath) - os.Setenv("GO111MODULE", "on") - - buildFlags, packages := "", []string{"main.go"} - _, err := NewBuild(buildFlags, packages, workingDir, "") - if !assert.Equal(t, err, ErrWrongPackageTypeForBuild) { - assert.FailNow(t, "should not success with non . or ./... package") - } -} - -// test NewBuild with wrong parameters -func TestNewBuildWithWrongParameters(t *testing.T) { - _, err := NewBuild("", []string{"a.go", "b.go"}, "cur", "cur") - assert.Equal(t, err, ErrTooManyArgs) - - _, err = NewBuild("", []string{"a.go"}, "", "cur") - assert.Equal(t, err, ErrInvalidWorkingDir) -} diff --git a/pkg/build/errors.go b/pkg/build/errors.go deleted file mode 100644 index e0376bd..0000000 --- a/pkg/build/errors.go +++ /dev/null @@ -1,24 +0,0 @@ -package build - -import ( - "errors" -) - -var ( - // ErrShouldNotReached represents the logic should not be reached in normal flow - ErrShouldNotReached = errors.New("should never be reached") - // ErrGocShouldExecInProject represents goc currently not support for the project - ErrGocShouldExecInProject = errors.New("goc not support for such project directory") - // ErrWrongPackageTypeForInstall represents goc install command only support limited arguments - ErrWrongPackageTypeForInstall = errors.New("packages only support \".\" and \"./...\"") - // ErrWrongPackageTypeForBuild represents goc build command only support limited arguments - ErrWrongPackageTypeForBuild = errors.New("packages only support \".\"") - // ErrTooManyArgs represents goc CLI only support limited arguments - ErrTooManyArgs = errors.New("too many args") - // ErrInvalidWorkingDir represents the working directory is invalid - ErrInvalidWorkingDir = errors.New("the working directory is invalid") - // ErrEmptyTempWorkingDir represent the error that temporary working directory is empty - ErrEmptyTempWorkingDir = errors.New("temporary working directory is empty") - // ErrNoPlaceToInstall represents the err that no place to install the generated binary - ErrNoPlaceToInstall = errors.New("don't know where to install") -) diff --git a/pkg/build/goenv.go b/pkg/build/goenv.go new file mode 100644 index 0000000..70d3ae1 --- /dev/null +++ b/pkg/build/goenv.go @@ -0,0 +1,116 @@ +package build + +import ( + "bytes" + "encoding/json" + "io" + "os" + "os/exec" + "path" + "path/filepath" + "strings" + + "github.com/qiniu/goc/v2/pkg/config" + "github.com/qiniu/goc/v2/pkg/log" +) + +// readProjectMetaInfo reads all meta informations of the corresponding project +func (b *Build) readProjectMetaInfo() { + // get gopath & gobin + config.GocConfig.GOPATH = b.readGOPATH() + config.GocConfig.GOBIN = b.readGOBIN() + // 获取 [packages] 及其依赖的 package list + pkgs := b.listPackages(config.GocConfig.CurWd) + + // get mod info + for _, pkg := range pkgs { + // check if go modules is enabled + if pkg.Module == nil { + log.Fatalf("Go module is not enabled, please set GO111MODULE=auto or on") + } + // 工程根目录 + config.GocConfig.CurModProjectDir = pkg.Root + config.GocConfig.ImportPath = pkg.Module.Path + + break + } + + // 如果当前目录不是工程根目录,那再次 go list 一次,获取整个工程的包信息 + if config.GocConfig.CurWd != config.GocConfig.CurModProjectDir { + config.GocConfig.Pkgs = b.listPackages(config.GocConfig.CurModProjectDir) + } else { + config.GocConfig.Pkgs = pkgs + } + + // get tmp folder name + config.GocConfig.TmpModProjectDir = filepath.Join(os.TempDir(), tmpFolderName(config.GocConfig.CurModProjectDir)) + // get working dir in the corresponding tmp dir + config.GocConfig.TmpWd = filepath.Join(config.GocConfig.TmpModProjectDir, config.GocConfig.CurWd[len(config.GocConfig.CurModProjectDir):]) + // get GlobalCoverVarImportPath + config.GocConfig.GlobalCoverVarImportPath = path.Join(config.GocConfig.ImportPath, tmpFolderName(config.GocConfig.CurModProjectDir)) + log.Donef("project meta information parsed") +} + +// displayProjectMetaInfo prints basic infomation of this project to stdout +func (b *Build) displayProjectMetaInfo() { + log.Infof("GOPATH: %v", config.GocConfig.GOPATH) + log.Infof("GOBIN: %v", config.GocConfig.GOBIN) + log.Infof("Project Directory: %v", config.GocConfig.CurModProjectDir) + log.Infof("Temporary Project Directory: %v", config.GocConfig.TmpModProjectDir) + log.Infof("") +} + +// readGOPATH reads GOPATH use go env GOPATH command +func (b *Build) readGOPATH() string { + out, err := exec.Command("go", "env", "GOPATH").Output() + if err != nil { + log.Fatalf("fail to read GOPATH: %v", err) + } + return strings.TrimSpace(string(out)) +} + +// readGOBIN reads GOBIN use go env GOBIN command +func (b *Build) readGOBIN() string { + out, err := exec.Command("go", "env", "GOBIN").Output() + if err != nil { + log.Fatalf("fail to read GOBIN: %v", err) + } + return strings.TrimSpace(string(out)) +} + +// listPackages list all packages under specific via go list command. +func (b *Build) listPackages(dir string) map[string]*config.Package { + cmd := exec.Command("go", "list", "-json", "./...") + cmd.Dir = dir + + var errBuf bytes.Buffer + cmd.Stderr = &errBuf + out, err := cmd.Output() + if err != nil { + log.Fatalf("execute go list -json failed, err: %v, stdout: %v, stderr: %v", err, string(out), errBuf.String()) + } + // 有些时候 go 命令会打印一些信息到 stderr,但其实命令整体是成功运行了 + if errBuf.String() != "" { + log.Errorf("%v", errBuf.String()) + } + + dec := json.NewDecoder(bytes.NewBuffer(out)) + pkgs := make(map[string]*config.Package, 0) + + for { + var pkg config.Package + if err := dec.Decode(&pkg); err != nil { + if err == io.EOF { + break + } + log.Fatalf("reading go list output error: %v", err) + } + if pkg.Error != nil { + log.Fatalf("list package %s failed with output: %v", pkg.ImportPath, pkg.Error) + } + + pkgs[pkg.ImportPath] = &pkg + } + + return pkgs +} diff --git a/pkg/build/gomodules.go b/pkg/build/gomodules.go deleted file mode 100644 index 82081f7..0000000 --- a/pkg/build/gomodules.go +++ /dev/null @@ -1,90 +0,0 @@ -/* - Copyright 2020 Qiniu Cloud (qiniu.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 ( - "io/ioutil" - "path/filepath" - - log "github.com/sirupsen/logrus" - "github.com/tongjingran/copy" - "golang.org/x/mod/modfile" -) - -func (b *Build) cpGoModulesProject() { - for _, v := range b.Pkgs { - if v.Name == "main" { - dst := b.TmpDir - src := v.Module.Dir - - if err := copy.Copy(src, dst, copy.Options{Skip: skipCopy}); err != nil { - log.Errorf("Failed to Copy the folder from %v to %v, the error is: %v ", src, dst, err) - } - break - } else { - continue - } - } -} - -// updateGoModFile rewrites the go.mod file in the temporary directory, -// if it has a 'replace' directive, and the directive has a relative local path -// it will be rewritten with a absolute path. -// ex. -// suppose original project is located at /path/to/aa/bb/cc, go.mod contains a directive: -// 'replace github.com/qiniu/bar => ../home/foo/bar' -// after the project is copied to temporary directory, it should be rewritten as -// 'replace github.com/qiniu/bar => /path/to/aa/bb/home/foo/bar' -func (b *Build) updateGoModFile() (updateFlag bool, newModFile []byte, err error) { - tempModfile := filepath.Join(b.TmpDir, "go.mod") - buf, err := ioutil.ReadFile(tempModfile) - if err != nil { - return - } - oriGoModFile, err := modfile.Parse(tempModfile, buf, nil) - if err != nil { - return - } - - updateFlag = false - for index := range oriGoModFile.Replace { - replace := oriGoModFile.Replace[index] - oldPath := replace.Old.Path - oldVersion := replace.Old.Version - newPath := replace.New.Path - newVersion := replace.New.Version - // replace to a local filesystem does not have a version - // absolute path no need to rewrite - if newVersion == "" && !filepath.IsAbs(newPath) { - var absPath string - fullPath := filepath.Join(b.ModRoot, newPath) - absPath, _ = filepath.Abs(fullPath) - // DropReplace & AddReplace will not return error - // so no need to check the error - _ = oriGoModFile.DropReplace(oldPath, oldVersion) - _ = oriGoModFile.AddReplace(oldPath, oldVersion, absPath, newVersion) - updateFlag = true - } - } - oriGoModFile.Cleanup() - // Format will not return error, so ignore the returned error - // func (f *File) Format() ([]byte, error) { - // return Format(f.Syntax), nil - // } - newModFile, _ = oriGoModFile.Format() - return -} diff --git a/pkg/build/gomodules_test.go b/pkg/build/gomodules_test.go deleted file mode 100644 index e0e6a6d..0000000 --- a/pkg/build/gomodules_test.go +++ /dev/null @@ -1,103 +0,0 @@ -/* - Copyright 2020 Qiniu Cloud (qiniu.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 ( - "bytes" - "errors" - "os" - "path/filepath" - "strings" - "testing" - - "github.com/qiniu/goc/pkg/cover" - log "github.com/sirupsen/logrus" - "github.com/stretchr/testify/assert" -) - -func captureOutput(f func()) string { - var buf bytes.Buffer - log.SetOutput(&buf) - f() - log.SetOutput(os.Stderr) - return buf.String() -} - -// copy in cpGoModulesProject of invalid src, dst name -func TestModProjectCopyWithUnexistedDir(t *testing.T) { - pkgs := make(map[string]*cover.Package) - pkgs["main"] = &cover.Package{ - Name: "main", - Module: &cover.ModulePublic{ - Dir: "not exied, ia mas duser", // not real one, should fail copy - }, - } - pkgs["another"] = &cover.Package{} - b := &Build{ - TmpDir: "sdfsfev2234444", // not real one, should fail copy - Pkgs: pkgs, - } - - output := captureOutput(b.cpGoModulesProject) - assert.Equal(t, strings.Contains(output, "Failed to Copy"), true) -} - -// test go mod file udpate -func TestUpdateModFileIfContainsReplace(t *testing.T) { - workingDir := filepath.Join(baseDir, "../../tests/samples/gomod_samples/a") - b := &Build{ - TmpDir: workingDir, - ModRoot: "/aa/bb/cc", - } - - // replace with relative local file path should be rewrite - updated, newmod, err := b.updateGoModFile() - assert.Equal(t, err, nil) - assert.Equal(t, updated, true) - assert.Contains(t, string(newmod), "replace github.com/qiniu/bar => /aa/bb/home/foo/bar") - - // old replace should be removed - assert.NotContains(t, string(newmod), "github.com/qiniu/bar => ../home/foo/bar") - - // normal replace should not be rewrite - assert.Contains(t, string(newmod), "github.com/qiniu/bar2 => github.com/baniu/bar3 v1.2.3") -} - -// test wrong go mod file -func TestWithWrongGoModFile(t *testing.T) { - // go.mod not exist - workingDir := filepath.Join(baseDir, "../../tests/samples/xxxxxxxxxxxx/a") - b := &Build{ - TmpDir: workingDir, - ModRoot: "/aa/bb/cc", - } - - updated, _, err := b.updateGoModFile() - assert.Equal(t, errors.Is(err, os.ErrNotExist), true) - assert.Equal(t, updated, false) - - // a wrong format go mod - workingDir = filepath.Join(baseDir, "../../tests/samples/gomod_samples/b") - b = &Build{ - TmpDir: workingDir, - ModRoot: "/aa/bb/cc", - } - - updated, _, err = b.updateGoModFile() - assert.NotEqual(t, err, nil) - assert.Equal(t, updated, false) -} diff --git a/pkg/build/install.go b/pkg/build/install.go index b5cb823..96bc3a7 100644 --- a/pkg/build/install.go +++ b/pkg/build/install.go @@ -1,87 +1,62 @@ -/* - Copyright 2020 Qiniu Cloud (qiniu.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" "os" "os/exec" - "strings" - log "github.com/sirupsen/logrus" + "github.com/qiniu/goc/v2/pkg/config" + "github.com/qiniu/goc/v2/pkg/cover" + "github.com/qiniu/goc/v2/pkg/log" + "github.com/spf13/cobra" ) -// NewInstall creates a Build struct which can install from goc temporary directory -func NewInstall(buildflags string, args []string, workingDir string) (*Build, error) { - if err := checkParameters(args, workingDir); err != nil { - return nil, err - } - b := &Build{ - BuildFlags: buildflags, - Packages: strings.Join(args, " "), - WorkingDir: workingDir, - } - if false == b.validatePackageForInstall() { - log.Errorln(ErrWrongPackageTypeForInstall) - return nil, ErrWrongPackageTypeForInstall - } - if err := b.MvProjectsToTmp(); err != nil { - return nil, err - } - return b, nil +func NewInstall(cmd *cobra.Command, args []string) *Build { + return NewBuild(cmd, args) } -// Install use the 'go install' tool to install packages -func (b *Build) Install() error { - log.Println("Go building in temp...") - cmd := exec.Command("/bin/bash", "-c", "go install "+b.BuildFlags+" "+b.Packages) - cmd.Dir = b.TmpWorkingDir +// Install starts go install +// +// 1. copy project to temp, +// 2. inject cover variables and functions into the project, +// 3. install the project in temp. +func (b *Build) Install() { + // 1. 拷贝至临时目录 + b.copyProjectToTmp() + defer b.clean() + + log.Donef("project copied to temporary directory") + // 2. inject cover vars + cover.Inject() + // 3. install in the temp project + b.doInstallInTemp() +} + +func (b *Build) doInstallInTemp() { + log.StartWait("installing the injected project") + + goflags := config.GocConfig.Goflags + + pacakges := config.GocConfig.Packages + + goflags = append(goflags, pacakges...) + + args := []string{"install"} + args = append(args, goflags...) + // go 命令行由 go install [build flags] [packages] 组成 + cmd := exec.Command("go", args...) + cmd.Dir = config.GocConfig.TmpWd cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr - whereToInstall, err := b.findWhereToInstall() - if err != nil { - // ignore the err - log.Errorf("No place to install: %v", err) + log.Infof("go install cmd is: %v, in path [%v]", cmd.Args, cmd.Dir) + if err := cmd.Start(); err != nil { + log.Fatalf("fail to execute go install: %v", err) } - // Change the temp GOBIN, to force binary install to original place - cmd.Env = append(os.Environ(), fmt.Sprintf("GOBIN=%v", whereToInstall)) - if b.NewGOPATH != "" { - // Change to temp GOPATH for go install command - cmd.Env = append(cmd.Env, fmt.Sprintf("GOPATH=%v", b.NewGOPATH)) + if err := cmd.Wait(); err != nil { + log.Fatalf("fail to execute go install: %v", err) } - log.Infof("go install cmd is: %v", cmd.Args) - err = cmd.Start() - if err != nil { - log.Errorf("Fail to execute: %v. The error is: %v", cmd.Args, err) - return err - } - if err = cmd.Wait(); err != nil { - log.Errorf("go install failed. The error is: %v", err) - return err - } - log.Infof("Go install successful. Binary installed in: %v", whereToInstall) - return nil -} - -func (b *Build) validatePackageForInstall() bool { - if b.Packages == "." || b.Packages == "" || b.Packages == "./..." { - return true - } - return false + // done + log.StopWait() + log.Donef("go install done") } diff --git a/pkg/build/install_test.go b/pkg/build/install_test.go deleted file mode 100644 index 30e996b..0000000 --- a/pkg/build/install_test.go +++ /dev/null @@ -1,42 +0,0 @@ -package build - -import ( - "os" - "path/filepath" - "testing" - - "github.com/stretchr/testify/assert" -) - -func TestBasicInstallForModProject(t *testing.T) { - workingDir := filepath.Join(baseDir, "../../tests/samples/simple_project") - gopath := filepath.Join(baseDir, "../../tests/samples/simple_project", "testhome") - - os.Setenv("GOPATH", gopath) - os.Setenv("GO111MODULE", "on") - - buildFlags, packages := "", []string{"."} - gocBuild, err := NewInstall(buildFlags, packages, workingDir) - if !assert.Equal(t, err, nil) { - assert.FailNow(t, "should create temporary directory successfully") - } - - err = gocBuild.Install() - if !assert.Equal(t, err, nil) { - assert.FailNow(t, "temporary directory should build successfully") - } -} - -func TestInvalidPackageNameForInstall(t *testing.T) { - workingDir := filepath.Join(baseDir, "../../tests/samples/simple_project") - gopath := filepath.Join(baseDir, "../../tests/samples/simple_project", "testhome") - - os.Setenv("GOPATH", gopath) - os.Setenv("GO111MODULE", "on") - - buildFlags, packages := "", []string{"main.go"} - _, err := NewInstall(buildFlags, packages, workingDir) - if !assert.Equal(t, err, ErrWrongPackageTypeForInstall) { - assert.FailNow(t, "should not success with non . or ./... package") - } -} diff --git a/pkg/build/legacy.go b/pkg/build/legacy.go deleted file mode 100644 index 5e20d68..0000000 --- a/pkg/build/legacy.go +++ /dev/null @@ -1,104 +0,0 @@ -/* - Copyright 2020 Qiniu Cloud (qiniu.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" - - log "github.com/sirupsen/logrus" - - "github.com/qiniu/goc/pkg/cover" - "github.com/tongjingran/copy" -) - -func (b *Build) cpLegacyProject() { - visited := make(map[string]bool) - for k, v := range b.Pkgs { - dst := filepath.Join(b.TmpDir, "src", k) - src := v.Dir - - if _, ok := visited[src]; ok { - // Skip if already copied - continue - } - - if err := copy.Copy(src, dst, copy.Options{Skip: skipCopy}); err != nil { - log.Errorf("Failed to Copy the folder from %v to %v, the error is: %v ", src, dst, err) - } - - visited[src] = true - - b.cpDepPackages(v, visited) - } -} - -// only cp dependency in root(current gopath), -// skip deps in other GOPATHs -func (b *Build) cpDepPackages(pkg *cover.Package, visited map[string]bool) { - gopath := pkg.Root - for _, dep := range pkg.Deps { - src := filepath.Join(gopath, "src", dep) - // Check if copied - if _, ok := visited[src]; ok { - // Skip if already copied - continue - } - // Check if we can found in the root gopath - _, err := os.Stat(src) - if err != nil { - continue - } - - dst := filepath.Join(b.TmpDir, "src", dep) - - if err := copy.Copy(src, dst, copy.Options{Skip: skipCopy}); err != nil { - log.Errorf("Failed to Copy the folder from %v to %v, the error is: %v ", src, dst, err) - } - - visited[src] = true - } -} - -func (b *Build) cpNonStandardLegacy() { - for _, v := range b.Pkgs { - if v.Name == "main" { - dst := b.TmpDir - src := v.Dir - - if err := copy.Copy(src, dst, copy.Options{Skip: skipCopy}); err != nil { - log.Printf("Failed to Copy the folder from %v to %v, the error is: %v ", src, dst, err) - } - break - } - } -} - -// skipCopy skip copy .git dir and irregular files -func skipCopy(src string, info os.FileInfo) (bool, error) { - irregularModeType := os.ModeNamedPipe | os.ModeSocket | os.ModeDevice | os.ModeCharDevice | os.ModeIrregular - if strings.HasSuffix(src, "/.git") { - log.Infof("Skip .git dir [%s]", src) - return true, nil - } - if info.Mode()&irregularModeType != 0 { - log.Warnf("Skip file [%s], the file mode is [%s]", src, info.Mode().String()) - return true, nil - } - return false, nil -} diff --git a/pkg/build/legacy_test.go b/pkg/build/legacy_test.go deleted file mode 100644 index ae2e5cc..0000000 --- a/pkg/build/legacy_test.go +++ /dev/null @@ -1,133 +0,0 @@ -/* - Copyright 2020 Qiniu Cloud (qiniu.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" - "testing" - "time" - - "github.com/qiniu/goc/pkg/cover" - "github.com/stretchr/testify/assert" -) - -// copy in cpLegacyProject/cpNonStandardLegacy of invalid src, dst name -func TestLegacyProjectCopyWithUnexistedDir(t *testing.T) { - pkgs := make(map[string]*cover.Package) - pkgs["main"] = &cover.Package{ - Module: &cover.ModulePublic{ - Dir: "not exied, ia mas duser", // not real one, should fail copy - }, - Dir: "not exit, iasdfs", - Name: "main", - } - pkgs["another"] = &cover.Package{} - b := &Build{ - TmpDir: "sdfsfev2234444", // not real one, should fail copy - Pkgs: pkgs, - } - - output := captureOutput(b.cpLegacyProject) - assert.Equal(t, strings.Contains(output, "Failed to Copy"), true) - - output = captureOutput(b.cpNonStandardLegacy) - assert.Equal(t, strings.Contains(output, "Failed to Copy"), true) -} - -// copy in cpDepPackages of invalid dst name -func TestDepPackagesCopyWithInvalidDir(t *testing.T) { - gopath := filepath.Join(baseDir, "../../tests/samples/simple_gopath_project") - pkg := &cover.Package{ - Module: &cover.ModulePublic{ - Dir: "not exied, ia mas duser", - }, - Root: gopath, - Deps: []string{"qiniu.com", "ddfee 2344234"}, - } - b := &Build{ - TmpDir: "/", // "/" is invalid dst in Linux, it should fail - } - - output := captureOutput(func() { - visited := make(map[string]bool) - - b.cpDepPackages(pkg, visited) - }) - assert.Equal(t, strings.Contains(output, "Failed to Copy"), true) -} - -type MockFile struct { - name string - size int64 - mode os.FileMode - modTime time.Time - isDir bool -} - -func (m MockFile) Name() string { - return m.name -} - -func (m MockFile) Size() int64 { - return m.size -} - -func (m MockFile) Mode() os.FileMode { - return m.mode -} - -func (m MockFile) ModTime() time.Time { - return m.modTime -} - -func (m MockFile) IsDir() bool { - return m.isDir -} - -func (m MockFile) Sys() interface{} { - return nil -} - -// skipCopy verify -func TestSkipCopy(t *testing.T) { - testCases := map[string]struct { - inputSrc string - inputInfo MockFile - expected bool - }{ - "src with /.git suffix": {inputSrc: "/test/.git", inputInfo: MockFile{mode: 0}, expected: true}, - "src with ./git suffix": {inputSrc: "/test.git", inputInfo: MockFile{mode: 0}, expected: false}, - "src with /.gita suffix": {inputSrc: "/test/.gita", inputInfo: MockFile{mode: 0}, expected: false}, - "src with /.git in middle": {inputSrc: "/test/.git/test", inputInfo: MockFile{mode: 0}, expected: false}, - "irregular file": {inputSrc: "/test", inputInfo: MockFile{mode: os.ModeIrregular}, expected: true}, - "dir file": {inputSrc: "/test", inputInfo: MockFile{isDir: true, mode: os.ModeDir}, expected: false}, - "temporary file": {inputSrc: "/test", inputInfo: MockFile{mode: os.ModeTemporary}, expected: false}, - "symlink file": {inputSrc: "/test", inputInfo: MockFile{mode: os.ModeSymlink}, expected: false}, - "device file": {inputSrc: "/test", inputInfo: MockFile{mode: os.ModeDevice}, expected: true}, - "named pipe file": {inputSrc: "/test", inputInfo: MockFile{mode: os.ModeNamedPipe}, expected: true}, - "socket file": {inputSrc: "/test", inputInfo: MockFile{mode: os.ModeSocket}, expected: true}, - } - for name, tc := range testCases { - t.Run(name, func(t *testing.T) { - output, err := skipCopy(tc.inputSrc, tc.inputInfo) - assert.NoError(t, err) - assert.Equal(t, output, tc.expected) - }) - } -} diff --git a/pkg/build/run.go b/pkg/build/run.go deleted file mode 100644 index 1a59219..0000000 --- a/pkg/build/run.go +++ /dev/null @@ -1,50 +0,0 @@ -/* - Copyright 2020 Qiniu Cloud (qiniu.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" - "os" - "os/exec" - - log "github.com/sirupsen/logrus" -) - -// Run excutes the main package in addition with the internal goc features -func (b *Build) Run() error { - cmd := exec.Command("/bin/bash", "-c", "go run "+b.BuildFlags+" "+b.GoRunExecFlag+" "+b.Packages+" "+b.GoRunArguments) - cmd.Dir = b.TmpWorkingDir - - if b.NewGOPATH != "" { - // Change to temp GOPATH for go install command - cmd.Env = append(os.Environ(), fmt.Sprintf("GOPATH=%v", b.NewGOPATH)) - } - - log.Infof("go build cmd is: %v", cmd.Args) - cmd.Stdout = os.Stdout - cmd.Stderr = os.Stderr - err := cmd.Start() - if err != nil { - return fmt.Errorf("fail to execute: %v, err: %w", cmd.Args, err) - } - - if err = cmd.Wait(); err != nil { - return fmt.Errorf("fail to execute: %v, err: %w", cmd.Args, err) - } - - return nil -} diff --git a/pkg/build/tmpfolder.go b/pkg/build/tmpfolder.go index 89b6ea2..1522835 100644 --- a/pkg/build/tmpfolder.go +++ b/pkg/build/tmpfolder.go @@ -1,212 +1,130 @@ -/* - Copyright 2020 Qiniu Cloud (qiniu.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 ( "crypto/sha256" - "errors" "fmt" "io/ioutil" "os" "path/filepath" "strings" - "github.com/qiniu/goc/pkg/cover" - log "github.com/sirupsen/logrus" - "github.com/spf13/viper" + "github.com/qiniu/goc/v2/pkg/config" + "github.com/qiniu/goc/v2/pkg/log" + "github.com/tongjingran/copy" + "golang.org/x/mod/modfile" ) -// MvProjectsToTmp moves the projects into a temporary directory -func (b *Build) MvProjectsToTmp() error { - listArgs := []string{"-json"} - if len(b.BuildFlags) != 0 { - listArgs = append(listArgs, b.BuildFlags) - } - listArgs = append(listArgs, "./...") - var err error - b.Pkgs, err = cover.ListPackages(b.WorkingDir, strings.Join(listArgs, " "), "") - if err != nil { - log.Errorln(err) - return err - } +// copyProjectToTmp copies project files to the temporary directory +// +// It will ignore .git and irregular files, only copy source(text) files +func (b *Build) copyProjectToTmp() { + curProject := config.GocConfig.CurModProjectDir + tmpProject := config.GocConfig.TmpModProjectDir - err = b.mvProjectsToTmp() - if err != nil { - log.Errorf("Fail to move the project to temporary directory") - return err - } - b.OriGOPATH = os.Getenv("GOPATH") - if b.IsMod == true { - b.NewGOPATH = "" - } else if b.OriGOPATH == "" { - b.NewGOPATH = b.TmpDir - } else { - b.NewGOPATH = fmt.Sprintf("%v:%v", b.TmpDir, b.OriGOPATH) - } - // fix #14: unable to build project not in GOPATH in legacy mode - // this kind of project does not have a pkg.Root value - // go 1.11, 1.12 has no pkg.Root, - // so add b.IsMod == false as secondary judgement - if b.Root == "" && b.IsMod == false { - b.NewGOPATH = b.OriGOPATH - } - log.Infof("New GOPATH: %v", b.NewGOPATH) - return nil -} - -func (b *Build) mvProjectsToTmp() error { - b.TmpDir = filepath.Join(os.TempDir(), tmpFolderName(b.WorkingDir)) - - // Delete previous tmp folder and its content - os.RemoveAll(b.TmpDir) - // Create a new tmp folder and a new importpath for storing cover variables - b.GlobalCoverVarImportPath = filepath.Join("src", tmpPackageName(b.WorkingDir)) - err := os.MkdirAll(filepath.Join(b.TmpDir, b.GlobalCoverVarImportPath), os.ModePerm) - if err != nil { - return fmt.Errorf("Fail to create the temporary build directory. The err is: %v", err) - } - log.Infof("Tmp project generated in: %v", b.TmpDir) - - // traverse pkg list to get project meta info - b.IsMod, b.Root, err = b.traversePkgsList() - log.Infof("mod project? %v", b.IsMod) - if errors.Is(err, ErrShouldNotReached) { - return fmt.Errorf("mvProjectsToTmp with a empty project: %w", err) - } - // we should get corresponding working directory in temporary directory - b.TmpWorkingDir, err = b.getTmpwd() - if err != nil { - return fmt.Errorf("getTmpwd failed with error: %w", err) - } - // issue #14 - // if b.Root == "", then the project is non-standard project - // known cases: - // 1. a legacy project, but not in any GOPATH, will cause the b.Root == "" - if b.IsMod == false && b.Root != "" { - b.cpLegacyProject() - } else if b.IsMod == true { // go 1.11, 1.12 has no Build.Root - b.cpGoModulesProject() - updated, newGoModContent, err := b.updateGoModFile() + if _, err := os.Stat(tmpProject); !os.IsNotExist(err) { + log.Infof("find previous temporary directory, delete") + err := os.RemoveAll(tmpProject) if err != nil { - return fmt.Errorf("fail to generate new go.mod: %v", err) + log.Fatalf("fail to remove preivous temporary directory: %v", err) } - if updated { - log.Infoln("go.mod needs rewrite") - tmpModFile := filepath.Join(b.TmpDir, "go.mod") - err := ioutil.WriteFile(tmpModFile, newGoModContent, os.ModePerm) - if err != nil { - return fmt.Errorf("fail to update go.mod: %v", err) - } - } - } else if b.IsMod == false && b.Root == "" { - b.TmpWorkingDir = b.TmpDir - b.cpNonStandardLegacy() } - log.Infof("New workingdir in tmp directory in: %v", b.TmpWorkingDir) - return nil + log.StartWait("coping project") + err := os.MkdirAll(tmpProject, os.ModePerm) + if err != nil { + log.Fatalf("fail to create temporary directory: %v", err) + } + + // copy + if err := copy.Copy(curProject, tmpProject, copy.Options{Skip: skipCopy}); err != nil { + log.Fatalf("fail to copy the folder from %v to %v, the err: %v", curProject, tmpProject, err) + } + + log.StopWait() } -// tmpFolderName uses the first six characters of the input path's SHA256 checksum -// as the suffix. +// tmpFolderName generates a directory name according to the path func tmpFolderName(path string) string { sum := sha256.Sum256([]byte(path)) h := fmt.Sprintf("%x", sum[:6]) - return "goc-build-" + h -} - -// tmpPackageName uses the first six characters of the input path's SHA256 checksum -// as the suffix. -func tmpPackageName(path string) string { - sum := sha256.Sum256([]byte(path)) - h := fmt.Sprintf("%x", sum[:6]) - return "gocbuild" + h } -// traversePkgsList travse the Build.Pkgs list -// return Build.IsMod, tell if the project is a mod project -// return Build.Root: -// 1. the project root if it is a mod project, -// 2. current GOPATH if it is a legacy project, -// 3. some non-standard project, which Build.IsMod == false, Build.Root == nil -func (b *Build) traversePkgsList() (isMod bool, root string, err error) { - for _, v := range b.Pkgs { - // get root - root = v.Root - if v.Module == nil { - return - } - isMod = true - b.ModRoot = v.Module.Dir - b.ModRootPath = v.Module.Path - return +// skipCopy skip copy .git dir and irregular files +func skipCopy(src string, info os.FileInfo) (bool, error) { + irregularModeType := os.ModeNamedPipe | os.ModeSocket | os.ModeDevice | os.ModeCharDevice | os.ModeIrregular + if strings.HasSuffix(src, "/.git") { + log.Debugf("skip .git dir [%s]", src) + return true, nil } - log.Error(ErrShouldNotReached) - err = ErrShouldNotReached + if info.Mode()&irregularModeType != 0 { + log.Debugf("skip file [%s], the file mode is [%s]", src, info.Mode().String()) + return true, nil + } + return false, nil +} + +// clean clears the temporary project +func (b *Build) clean() { + if config.GocConfig.Debug != true { + if err := os.RemoveAll(config.GocConfig.TmpModProjectDir); err != nil { + log.Fatalf("fail to delete the temporary project: %v", err) + } + log.Donef("delete the temporary project") + } else { + log.Debugf("--debug is enabled, keep the temporary project") + } +} + +// updateGoModFile rewrites the go.mod file in the temporary directory, +// +// if it has a 'replace' directive, and the directive has a relative local path, +// it will be rewritten with a absolute path. +// +// ex. +// +// suppose original project is located at /path/to/aa/bb/cc, go.mod contains a directive: +// 'replace github.com/qiniu/bar => ../home/foo/bar' +// +// after the project is copied to temporary directory, it should be rewritten as +// 'replace github.com/qiniu/bar => /path/to/aa/bb/home/foo/bar' +func (b *Build) updateGoModFile() (updateFlag bool, newModFile []byte) { + tempModfile := filepath.Join(config.GocConfig.TmpModProjectDir, "go.mod") + buf, err := ioutil.ReadFile(tempModfile) + if err != nil { + log.Fatalf("cannot find go.mod file in temporary directory: %v", err) + } + oriGoModFile, err := modfile.Parse(tempModfile, buf, nil) + if err != nil { + log.Fatalf("cannot parse go.mod: %v", err) + } + + updateFlag = false + for index := range oriGoModFile.Replace { + replace := oriGoModFile.Replace[index] + oldPath := replace.Old.Path + oldVersion := replace.Old.Version + newPath := replace.New.Path + newVersion := replace.New.Version + // replace to a local filesystem does not have a version + // absolute path no need to rewrite + if newVersion == "" && !filepath.IsAbs(newPath) { + var absPath string + fullPath := filepath.Join(config.GocConfig.CurModProjectDir, newPath) + absPath, _ = filepath.Abs(fullPath) + // DropReplace & AddReplace will not return error + // so no need to check the error + _ = oriGoModFile.DropReplace(oldPath, oldVersion) + _ = oriGoModFile.AddReplace(oldPath, oldVersion, absPath, newVersion) + updateFlag = true + } + } + oriGoModFile.Cleanup() + // Format will not return error, so ignore the returned error + // func (f *File) Format() ([]byte, error) { + // return Format(f.Syntax), nil + // } + newModFile, _ = oriGoModFile.Format() return } - -// getTmpwd get the corresponding working directory in the temporary working directory -// and store it in the Build.tmpWorkdingDir -func (b *Build) getTmpwd() (string, error) { - for _, pkg := range b.Pkgs { - var index int - var parentPath string - if b.IsMod == false { - index = strings.Index(b.WorkingDir, pkg.Root) - parentPath = pkg.Root - } else { - index = strings.Index(b.WorkingDir, pkg.Module.Dir) - parentPath = pkg.Module.Dir - } - - if index == -1 { - return "", ErrGocShouldExecInProject - } - // b.TmpWorkingDir = filepath.Join(b.TmpDir, path[len(parentPath):]) - return filepath.Join(b.TmpDir, b.WorkingDir[len(parentPath):]), nil - } - - return "", ErrShouldNotReached -} - -func (b *Build) findWhereToInstall() (string, error) { - if GOBIN := os.Getenv("GOBIN"); GOBIN != "" { - return GOBIN, nil - } - - if false == b.IsMod { - if b.Root == "" { - return "", ErrNoPlaceToInstall - } - return filepath.Join(b.Root, "bin"), nil - } - if b.OriGOPATH != "" { - return filepath.Join(strings.Split(b.OriGOPATH, ":")[0], "bin"), nil - } - return filepath.Join(os.Getenv("HOME"), "go", "bin"), nil -} - -// Clean clears up the temporary workspace -func (b *Build) Clean() error { - if !viper.GetBool("debug") { - return os.RemoveAll(b.TmpDir) - } - return nil -} diff --git a/pkg/build/tmpfolder_test.go b/pkg/build/tmpfolder_test.go deleted file mode 100644 index 2183280..0000000 --- a/pkg/build/tmpfolder_test.go +++ /dev/null @@ -1,150 +0,0 @@ -/* - Copyright 2020 Qiniu Cloud (qiniu.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" - "os" - "path/filepath" - "strings" - "testing" - - "github.com/stretchr/testify/assert" -) - -var baseDir string - -func init() { - baseDir, _ = os.Getwd() -} - -func TestNewDirParseInLegacyProject(t *testing.T) { - workingDir := filepath.Join(baseDir, "../../tests/samples/simple_gopath_project/src/qiniu.com/simple_gopath_project") - gopath := filepath.Join(baseDir, "../../tests/samples/simple_gopath_project") - - os.Setenv("GOPATH", gopath) - os.Setenv("GO111MODULE", "off") - - b, _ := NewInstall("", []string{"."}, workingDir) - if -1 == strings.Index(b.TmpWorkingDir, b.TmpDir) { - t.Fatalf("Directory parse error. newwd: %v, tmpdir: %v", b.TmpWorkingDir, b.TmpDir) - } - - if -1 == strings.Index(b.NewGOPATH, ":") || -1 == strings.Index(b.NewGOPATH, b.TmpDir) { - t.Fatalf("The New GOPATH is wrong. newgopath: %v, tmpdir: %v", b.NewGOPATH, b.TmpDir) - } - - b, _ = NewBuild("", []string{"."}, workingDir, "") - if -1 == strings.Index(b.TmpWorkingDir, b.TmpDir) { - t.Fatalf("Directory parse error. newwd: %v, tmpdir: %v", b.TmpWorkingDir, b.TmpDir) - } - - if -1 == strings.Index(b.NewGOPATH, ":") || -1 == strings.Index(b.NewGOPATH, b.TmpDir) { - t.Fatalf("The New GOPATH is wrong. newgopath: %v, tmpdir: %v", b.NewGOPATH, b.TmpDir) - } -} - -func TestNewDirParseInModProject(t *testing.T) { - workingDir := filepath.Join(baseDir, "../../tests/samples/simple_project") - gopath := "" - - fmt.Println(gopath) - os.Setenv("GOPATH", gopath) - os.Setenv("GO111MODULE", "on") - - b, _ := NewInstall("", []string{"."}, workingDir) - if -1 == strings.Index(b.TmpWorkingDir, b.TmpDir) { - t.Fatalf("Directory parse error. newwd: %v, tmpdir: %v", b.TmpWorkingDir, b.TmpDir) - } - - if b.NewGOPATH != "" { - t.Fatalf("The New GOPATH is wrong. newgopath: %v, tmpdir: %v", b.NewGOPATH, b.TmpDir) - } - - b, _ = NewBuild("", []string{"."}, workingDir, "") - if -1 == strings.Index(b.TmpWorkingDir, b.TmpDir) { - t.Fatalf("Directory parse error. newwd: %v, tmpdir: %v", b.TmpWorkingDir, b.TmpDir) - } - - if b.NewGOPATH != "" { - t.Fatalf("The New GOPATH is wrong. newgopath: %v, tmpdir: %v", b.NewGOPATH, b.TmpDir) - } -} - -// Test #14 -func TestLegacyProjectNotInGoPATH(t *testing.T) { - workingDir := filepath.Join(baseDir, "../../tests/samples/simple_gopath_project/src/qiniu.com/simple_gopath_project") - gopath := "" - - fmt.Println(gopath) - os.Setenv("GOPATH", gopath) - os.Setenv("GO111MODULE", "off") - - b, _ := NewBuild("", []string{"."}, workingDir, "") - if b.OriGOPATH != b.NewGOPATH { - t.Fatalf("New GOPATH should be same with old GOPATH, for this kind of project. New: %v, old: %v", b.NewGOPATH, b.OriGOPATH) - } - - _, err := os.Stat(filepath.Join(b.TmpDir, "main.go")) - if err != nil { - t.Fatalf("There should be a main.go in temporary directory directly, the error: %v", err) - } -} - -// test traversePkgsList error case -func TestTraversePkgsList(t *testing.T) { - b := &Build{ - Pkgs: nil, - } - _, _, err := b.traversePkgsList() - assert.EqualError(t, err, ErrShouldNotReached.Error()) -} - -// test getTmpwd error case -func TestGetTmpwd(t *testing.T) { - b := &Build{ - Pkgs: nil, - } - _, err := b.getTmpwd() - assert.EqualError(t, err, ErrShouldNotReached.Error()) -} - -// test findWhereToInstall -func TestFindWhereToInstall(t *testing.T) { - // if a legacy project without project root find - // should find no plcae to install - b := &Build{ - Pkgs: nil, - IsMod: false, - Root: "", - } - _, err := b.findWhereToInstall() - assert.EqualError(t, err, ErrNoPlaceToInstall.Error()) - - // if $GOBIN not found - // and if $GOPATH not found - // should install to $HOME/go/bin - b = &Build{ - Pkgs: nil, - IsMod: true, - OriGOPATH: "", - } - placeToInstall, err := b.findWhereToInstall() - assert.NoError(t, err) - expectedPlace := filepath.Join(os.Getenv("HOME"), "go", "bin") - assert.Equal(t, placeToInstall, expectedPlace) -} diff --git a/pkg/config/config.go b/pkg/config/config.go new file mode 100644 index 0000000..581698e --- /dev/null +++ b/pkg/config/config.go @@ -0,0 +1,134 @@ +package config + +import "time" + +type gocConfig struct { + Debug bool + Host string + Mode string // cover mode + + GOPATH string + GOBIN string + CurWd string + TmpWd string + CurModProjectDir string + TmpModProjectDir string + + Goflags []string // command line flags + Packages []string // command line [packages] + + ImportPath string // the whole import path of the project + Pkgs map[string]*Package + GlobalCoverVarImportPath string + GlobalCoverVarImportPathDir string +} + +// GocConfig 全局变量,存放 goc 的各种元属性 +var GocConfig gocConfig + +type goConfig struct { + BuildA bool + BuildBuildmode string // -buildmode flag + BuildMod string // -mod flag + BuildModReason string // reason -mod flag is set, if set by default + BuildI bool // -i flag + BuildLinkshared bool // -linkshared flag + BuildMSan bool // -msan flag + BuildN bool // -n flag + BuildO string // -o flag + BuildP int // -p flag + BuildPkgdir string // -pkgdir flag + BuildRace bool // -race flag + BuildToolexec string // -toolexec flag + BuildToolchainName string + BuildToolchainCompiler func() string + BuildToolchainLinker func() string + BuildTrimpath bool // -trimpath flag + BuildV bool // -v flag + BuildWork bool // -work flag + BuildX bool // -x flag + // from buildcontext + Installsuffix string // -installSuffix + BuildTags string // -tags + // from load + BuildAsmflags string + BuildCompiler string + BuildGcflags string + BuildGccgoflags string + BuildLdflags string + + // mod related + ModCacheRW bool + ModFile string +} + +var GoConfig goConfig + +// PackageCover holds all the generate coverage variables of a package +type PackageCover struct { + Package *Package + Vars map[string]*FileVar +} + +// FileVar holds the name of the generated coverage variables targeting the named file. +type FileVar struct { + File string // 这里其实不是文件名,是 importpath + filename + Var string +} + +// Package map a package output by go list +// this is subset of package struct in: https://github.com/golang/go/blob/master/src/cmd/go/internal/load/pkg.go#L58 +type Package struct { + Dir string `json:"Dir"` // directory containing package sources + ImportPath string `json:"ImportPath"` // import path of package in dir + Name string `json:"Name"` // package name + Target string `json:",omitempty"` // installed target for this package (may be executable) + Root string `json:",omitempty"` // Go root, Go path dir, or module root dir containing this package + + Module *ModulePublic `json:",omitempty"` // info about package's module, if any + Goroot bool `json:"Goroot,omitempty"` // is this package in the Go root? + Standard bool `json:"Standard,omitempty"` // is this package part of the standard Go library? + DepOnly bool `json:"DepOnly,omitempty"` // package is only a dependency, not explicitly listed + + // Source files + GoFiles []string `json:"GoFiles,omitempty"` // .go source files (excluding CgoFiles, TestGoFiles, XTestGoFiles) + CgoFiles []string `json:"CgoFiles,omitempty"` // .go source files that import "C" + + // Dependency information + Deps []string `json:"Deps,omitempty"` // all (recursively) imported dependencies + Imports []string `json:",omitempty"` // import paths used by this package + ImportMap map[string]string `json:",omitempty"` // map from source import to ImportPath (identity entries omitted) + + // Error information + Incomplete bool `json:"Incomplete,omitempty"` // this package or a dependency has an error + Error *PackageError `json:"Error,omitempty"` // error loading package + DepsErrors []*PackageError `json:"DepsErrors,omitempty"` // errors loading dependencies +} + +// ModulePublic represents the package info of a module +type ModulePublic struct { + Path string `json:",omitempty"` // module path + Version string `json:",omitempty"` // module version + Versions []string `json:",omitempty"` // available module versions + Replace *ModulePublic `json:",omitempty"` // replaced by this module + Time *time.Time `json:",omitempty"` // time version was created + Update *ModulePublic `json:",omitempty"` // available update (with -u) + Main bool `json:",omitempty"` // is this the main module? + Indirect bool `json:",omitempty"` // module is only indirectly needed by main module + Dir string `json:",omitempty"` // directory holding local copy of files, if any + GoMod string `json:",omitempty"` // path to go.mod file describing module, if any + GoVersion string `json:",omitempty"` // go version used in module + Error *ModuleError `json:",omitempty"` // error loading module +} + +// ModuleError represents the error loading module +type ModuleError struct { + Err string // error text +} + +// PackageError is the error info for a package when list failed +type PackageError struct { + ImportStack []string // shortest path from package named on command line to this one + Pos string // position of error (if present, file:line:col) + Err string // the error itself +} diff --git a/pkg/cover/agent.tpl b/pkg/cover/agent.tpl new file mode 100644 index 0000000..64d32aa --- /dev/null +++ b/pkg/cover/agent.tpl @@ -0,0 +1,276 @@ +package cover + +import ( + "fmt" + "io" + "log" + "net/rpc" + "net/rpc/jsonrpc" + "net/url" + "os" + "strconv" + "strings" + "sync/atomic" + "time" + "testing" + + "{{.GlobalCoverVarImportPath}}/websocket" + + _cover "{{.GlobalCoverVarImportPath}}" +) + +var ( + waitDelay time.Duration = 10 * time.Second + host string = "{{.Host}}" +) + +func init() { + // init host + host_env := os.Getenv("GOC_CUSTOM_HOST") + if host_env != "" { + host = host_env + } + + var dialer = websocket.DefaultDialer + + go func() { + // 永不退出,出错后统一操作为:延时 + conitnue + for { + // 获取进程元信息用于注册 + ps, err := getRegisterInfo() + if err != nil { + time.Sleep(waitDelay) + continue + } + + // 注册,直接将元信息放在 ws 地址中 + v := url.Values{} + v.Set("hostname", ps.hostname) + v.Set("pid", strconv.Itoa(ps.pid)) + v.Set("cmdline", ps.cmdline) + v.Encode() + + rpcstreamUrl := fmt.Sprintf("ws://%v/v2/internal/ws/rpcstream?%v", host, v.Encode()) + ws, _, err := dialer.Dial(rpcstreamUrl, nil) + if err != nil { + log.Printf("[goc][Error] rpc fail to dial to goc server: %v", err) + time.Sleep(waitDelay) + continue + } + log.Printf("[goc][Info] rpc connected to goc server") + + rwc := &ReadWriteCloser{ws: ws} + s := rpc.NewServer() + s.Register(&GocAgent{}) + s.ServeCodec(jsonrpc.NewServerCodec(rwc)) + + // exit rpc server, close ws connection + ws.Close() + time.Sleep(waitDelay) + log.Printf("[goc][Error] rpc connection to goc server broken", ) + } + }() +} + +// rpc +type GocAgent struct { +} + +type ProfileReq string + +type ProfileRes string + +// return a profile of now +func (ga *GocAgent) GetProfile(req *ProfileReq, res *ProfileRes) error { + if *req != "getprofile" { + *res = "" + return fmt.Errorf("wrong command") + } + + w := new(strings.Builder) + fmt.Fprint(w, "mode: {{.Mode}}\n") + + counters, blocks := loadValues() + var active, total int64 + var count uint32 + for name, counts := range counters { + block := blocks[name] + for i := range counts { + stmts := int64(block[i].Stmts) + total += stmts + count = atomic.LoadUint32(&counts[i]) // For -mode=atomic. + if count > 0 { + active += stmts + } + _, err := fmt.Fprintf(w, "%s:%d.%d,%d.%d %d %d\n", name, + block[i].Line0, block[i].Col0, + block[i].Line1, block[i].Col1, + stmts, + count) + if err != nil { + fmt.Fprintf(w, "invalid block format, err: %v", err) + return err + } + } + } + + *res = ProfileRes(w.String()) + + return nil +} + +// reset profile to 0 +func (ga *GocAgent) ResetProfile(req *ProfileReq, res *ProfileRes) error { + if *req != "resetprofile" { + *res = "" + return fmt.Errorf("wrong command") + } + + resetValues() + + *res = `ok` + + return nil +} + +// get cover Values + +func loadValues() (map[string][]uint32, map[string][]testing.CoverBlock) { + var ( + coverCounters = make(map[string][]uint32) + coverBlocks = make(map[string][]testing.CoverBlock) + ) + + {{range $i, $pkgCover := .Covers}} + {{range $file, $cover := $pkgCover.Vars}} + loadFileCover(coverCounters, coverBlocks, "{{$cover.File}}", _cover.{{$cover.Var}}.Count[:], _cover.{{$cover.Var}}.Pos[:], _cover.{{$cover.Var}}.NumStmt[:]) + {{end}} + {{end}} + + return coverCounters, coverBlocks +} + +func loadFileCover(coverCounters map[string][]uint32, coverBlocks map[string][]testing.CoverBlock, fileName string, counter []uint32, pos []uint32, numStmts []uint16) { + if 3*len(counter) != len(pos) || len(counter) != len(numStmts) { + panic("coverage: mismatched sizes") + } + if coverCounters[fileName] != nil { + // Already registered. + return + } + coverCounters[fileName] = counter + block := make([]testing.CoverBlock, len(counter)) + for i := range counter { + block[i] = testing.CoverBlock{ + Line0: pos[3*i+0], + Col0: uint16(pos[3*i+2]), + Line1: pos[3*i+1], + Col1: uint16(pos[3*i+2] >> 16), + Stmts: numStmts[i], + } + } + coverBlocks[fileName] = block +} + +// reset counters +func resetValues() { + {{range $i, $pkgCover := .Covers}} + {{range $file, $cover := $pkgCover.Vars}} + clearFileCover(_cover.{{$cover.Var}}.Count[:]) + {{end}} + {{end}} +} + +func clearFileCover(counter []uint32) { + for i := range counter { + counter[i] = 0 + } +} + + +// get process meta info for register +type processInfo struct { + hostname string + pid int + cmdline string +} + +func getRegisterInfo() (*processInfo, error) { + hostname, err := os.Hostname() + if err != nil { + log.Printf("[goc][Error] fail to get hostname: %v", hostname) + return nil, err + } + + pid := os.Getpid() + + cmdline := os.Args[0] + + return &processInfo{ + hostname: hostname, + pid: pid, + cmdline: cmdline, + }, nil +} + +/// websocket rpc readwriter closer + +type ReadWriteCloser struct { + ws *websocket.Conn + r io.Reader + w io.WriteCloser +} + +func (rwc *ReadWriteCloser) Read(p []byte) (n int, err error) { + if rwc.r == nil { + var _ int + _, rwc.r, err = rwc.ws.NextReader() + if err != nil { + return 0, err + } + } + for n = 0; n < len(p); { + var m int + m, err = rwc.r.Read(p[n:]) + n += m + if err == io.EOF { + // done + rwc.r = nil + break + } + // ??? + if err != nil { + break + } + } + return +} + +func (rwc *ReadWriteCloser) Write(p []byte) (n int, err error) { + if rwc.w == nil { + rwc.w, err = rwc.ws.NextWriter(websocket.TextMessage) + if err != nil { + return 0, err + } + } + for n = 0; n < len(p); { + var m int + m, err = rwc.w.Write(p) + n += m + if err != nil { + break + } + } + if err != nil || n == len(p) { + err = rwc.Close() + } + return +} + +func (rwc *ReadWriteCloser) Close() (err error) { + if rwc.w != nil { + err = rwc.w.Close() + rwc.w = nil + } + return err +} diff --git a/pkg/cover/agentwatch.tpl b/pkg/cover/agentwatch.tpl new file mode 100644 index 0000000..c0ddc89 --- /dev/null +++ b/pkg/cover/agentwatch.tpl @@ -0,0 +1,151 @@ +package coverdef + +import ( + "fmt" + "time" + "os" + "log" + "strconv" + "net/url" + + "{{.GlobalCoverVarImportPath}}/websocket" +) + +var ( + watchChannel = make(chan *blockInfo, 1024) + + watchEnabled = false + + waitDelay time.Duration = 10 * time.Second + host string = "{{.Host}}" +) + +func init() { + // init host + host_env := os.Getenv("GOC_CUSTOM_HOST") + if host_env != "" { + host = host_env + } + + var dialer = websocket.DefaultDialer + + go func() { + for { + // 获取进程元信息用于注册 + ps, err := getRegisterInfo() + if err != nil { + time.Sleep(waitDelay) + continue + } + + // 注册,直接将元信息放在 ws 地址中 + v := url.Values{} + v.Set("hostname", ps.hostname) + v.Set("pid", strconv.Itoa(ps.pid)) + v.Set("cmdline", ps.cmdline) + v.Encode() + + watchstreamUrl := fmt.Sprintf("ws://%v/v2/internal/ws/watchstream?%v", host, v.Encode()) + ws, _, err := dialer.Dial(watchstreamUrl, nil) + if err != nil { + log.Printf("[goc][Error] watch fail to dial to goc server: %v", err) + time.Sleep(waitDelay) + continue + } + + // 连接成功 + watchEnabled = true + log.Printf("[goc][Info] watch connected to goc server") + + ticker := time.NewTicker(time.Second) + closeFlag := false + go func() { + for { + // 必须调用一下以触发 ping 的自动处理 + _, _, err := ws.ReadMessage() + if err != nil { + break + } + } + closeFlag = true + }() + + Loop: + for { + select { + case block := <-watchChannel: + i := block.i + + cov := fmt.Sprintf("%s:%d.%d,%d.%d %d %d", block.name, + block.pos[3*i+0], uint16(block.pos[3*i+2]), + block.pos[3*i+1], uint16(block.pos[3*i+2] >> 16), + 1, + 0) + + err = ws.WriteMessage(websocket.TextMessage, []byte(cov)) + if err != nil { + watchEnabled = false + log.Println("[goc][Error] push coverage failed: %v", err) + time.Sleep(waitDelay) + break Loop + } + case <-ticker.C: + if closeFlag == true { + break Loop + } + } + } + } + }() +} + +// get process meta info for register +type processInfo struct { + hostname string + pid int + cmdline string +} + +func getRegisterInfo() (*processInfo, error) { + hostname, err := os.Hostname() + if err != nil { + log.Printf("[goc][Error] fail to get hostname: %v", hostname) + return nil, err + } + + pid := os.Getpid() + + cmdline := os.Args[0] + + return &processInfo{ + hostname: hostname, + pid: pid, + cmdline: cmdline, + }, nil +} + +// + +type blockInfo struct { + name string + pos []uint32 + i int +} + +// UploadCoverChangeEvent_{{.Random}} is non-blocking +func UploadCoverChangeEvent_{{.Random}}(name string, pos []uint32, i int) { + + if watchEnabled == false { + return + } + + // make sure send is non-blocking + select { + case watchChannel <- &blockInfo{ + name: name, + pos: pos, + i: i, + }: + default: + } +} diff --git a/pkg/cover/client.go b/pkg/cover/client.go deleted file mode 100644 index 827c7c8..0000000 --- a/pkg/cover/client.go +++ /dev/null @@ -1,188 +0,0 @@ -/* - Copyright 2020 Qiniu Cloud (qiniu.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 cover - -import ( - "bytes" - "encoding/json" - "fmt" - "io" - "io/ioutil" - "net" - "net/http" - "net/url" - "strings" - - log "github.com/sirupsen/logrus" -) - -// Action provides methods to contact with the covered service under test -type Action interface { - Profile(param ProfileParam) ([]byte, error) - Clear(param ProfileParam) ([]byte, error) - Remove(param ProfileParam) ([]byte, error) - InitSystem() ([]byte, error) - ListServices() ([]byte, error) - RegisterService(svr ServiceUnderTest) ([]byte, error) -} - -const ( - //CoverInitSystemAPI prepare a new round of testing - CoverInitSystemAPI = "/v1/cover/init" - //CoverProfileAPI is provided by the covered service to get profiles - CoverProfileAPI = "/v1/cover/profile" - //CoverProfileClearAPI is provided by the covered service to clear profiles - CoverProfileClearAPI = "/v1/cover/clear" - //CoverServicesListAPI list all the registered services - CoverServicesListAPI = "/v1/cover/list" - //CoverRegisterServiceAPI register a service into service center - CoverRegisterServiceAPI = "/v1/cover/register" - //CoverServicesRemoveAPI remove one services from the service center - CoverServicesRemoveAPI = "/v1/cover/remove" -) - -type client struct { - Host string - client *http.Client -} - -// NewWorker creates a worker to contact with service -func NewWorker(host string) Action { - _, err := url.ParseRequestURI(host) - if err != nil { - log.Fatalf("Parse url %s failed, err: %v", host, err) - } - return &client{ - Host: host, - client: http.DefaultClient, - } -} - -func (c *client) RegisterService(srv ServiceUnderTest) ([]byte, error) { - if _, err := url.ParseRequestURI(srv.Address); err != nil { - return nil, err - } - if strings.TrimSpace(srv.Name) == "" { - return nil, fmt.Errorf("invalid service name") - } - u := fmt.Sprintf("%s%s?name=%s&address=%s", c.Host, CoverRegisterServiceAPI, srv.Name, srv.Address) - _, res, err := c.do("POST", u, "", nil) - return res, err -} - -func (c *client) ListServices() ([]byte, error) { - u := fmt.Sprintf("%s%s", c.Host, CoverServicesListAPI) - _, services, err := c.do("GET", u, "", nil) - if err != nil && isNetworkError(err) { - _, services, err = c.do("GET", u, "", nil) - } - - return services, err -} - -func (c *client) Profile(param ProfileParam) ([]byte, error) { - u := fmt.Sprintf("%s%s", c.Host, CoverProfileAPI) - if len(param.Service) != 0 && len(param.Address) != 0 { - return nil, fmt.Errorf("use 'service' flag and 'address' flag at the same time may cause ambiguity, please use them separately") - } - - // the json.Marshal function can return two types of errors: UnsupportedTypeError or UnsupportedValueError - // so no need to check here - body, _ := json.Marshal(param) - - res, profile, err := c.do("POST", u, "application/json", bytes.NewReader(body)) - if err != nil && isNetworkError(err) { - res, profile, err = c.do("POST", u, "application/json", bytes.NewReader(body)) - } - - if err == nil && res.StatusCode != 200 { - err = fmt.Errorf(string(profile)) - } - return profile, err -} - -func (c *client) Clear(param ProfileParam) ([]byte, error) { - u := fmt.Sprintf("%s%s", c.Host, CoverProfileClearAPI) - if len(param.Service) != 0 && len(param.Address) != 0 { - return nil, fmt.Errorf("use 'service' flag and 'address' flag at the same time may cause ambiguity, please use them separately") - } - - // the json.Marshal function can return two types of errors: UnsupportedTypeError or UnsupportedValueError - // so no need to check here - body, _ := json.Marshal(param) - _, resp, err := c.do("POST", u, "application/json", bytes.NewReader(body)) - if err != nil && isNetworkError(err) { - _, resp, err = c.do("POST", u, "application/json", bytes.NewReader(body)) - } - return resp, err -} - -func (c *client) Remove(param ProfileParam) ([]byte, error) { - u := fmt.Sprintf("%s%s", c.Host, CoverServicesRemoveAPI) - if len(param.Service) != 0 && len(param.Address) != 0 { - return nil, fmt.Errorf("use 'service' flag and 'address' flag at the same time may cause ambiguity, please use them separately") - } - - // the json.Marshal function can return two types of errors: UnsupportedTypeError or UnsupportedValueError - // so no need to check here - body, err := json.Marshal(param) - if err != nil { - return nil, err - } - _, resp, err := c.do("POST", u, "application/json", bytes.NewReader(body)) - if err != nil && isNetworkError(err) { - _, resp, err = c.do("POST", u, "application/json", bytes.NewReader(body)) - } - return resp, err -} - -func (c *client) InitSystem() ([]byte, error) { - u := fmt.Sprintf("%s%s", c.Host, CoverInitSystemAPI) - _, body, err := c.do("POST", u, "", nil) - return body, err -} - -func (c *client) do(method, url, contentType string, body io.Reader) (*http.Response, []byte, error) { - req, err := http.NewRequest(method, url, body) - if err != nil { - return nil, nil, err - } - - if contentType != "" { - req.Header.Set("Content-Type", contentType) - } - - res, err := c.client.Do(req) - if err != nil { - return nil, nil, err - } - defer res.Body.Close() - - responseBody, err := ioutil.ReadAll(res.Body) - if err != nil { - return res, nil, err - } - return res, responseBody, nil -} - -func isNetworkError(err error) bool { - if err == io.EOF { - return true - } - _, ok := err.(net.Error) - return ok -} diff --git a/pkg/cover/client_test.go b/pkg/cover/client_test.go deleted file mode 100644 index 4313dfe..0000000 --- a/pkg/cover/client_test.go +++ /dev/null @@ -1,257 +0,0 @@ -/* - Copyright 2020 Qiniu Cloud (qiniu.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 cover - -import ( - "fmt" - "net/http/httptest" - "os" - "testing" - - "net/http" - - "github.com/stretchr/testify/assert" -) - -func TestClientAction(t *testing.T) { - // mock goc server - server, err := NewFileBasedServer("_svrs_address.txt") - assert.NoError(t, err) - ts := httptest.NewServer(server.Route(os.Stdout)) - defer ts.Close() - var client = NewWorker(ts.URL) - - // mock profile server - profileMockResponse := []byte("mode: count\nmockService/main.go:30.13,48.33 13 1\nb/b.go:30.13,48.33 13 1") - profileSuccessMockSvr := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - w.WriteHeader(http.StatusOK) - _, _ = w.Write(profileMockResponse) - })) - defer profileSuccessMockSvr.Close() - - profileErrMockSvr := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - w.WriteHeader(http.StatusOK) - w.Write([]byte("error")) - })) - defer profileErrMockSvr.Close() - - // register service into goc server - var src ServiceUnderTest - src.Name = "serviceSuccess" - src.Address = profileSuccessMockSvr.URL - res, err := client.RegisterService(src) - assert.NoError(t, err) - assert.Contains(t, string(res), "success") - - // do list and check server - res, err = client.ListServices() - assert.NoError(t, err) - assert.Contains(t, string(res), src.Address) - assert.Contains(t, string(res), src.Name) - - // get profile from goc server - tcs := []struct { - name string - service ServiceUnderTest - param ProfileParam - expected string - expectedErr bool - }{ - { - name: "both server and address existed", - service: ServiceUnderTest{Name: "serviceOK", Address: profileSuccessMockSvr.URL}, - param: ProfileParam{Force: false, Service: []string{"serviceOK"}, Address: []string{profileSuccessMockSvr.URL}}, - expectedErr: true, - }, - { - name: "valid test with no server flag provide", - service: ServiceUnderTest{Name: "serviceOK", Address: profileSuccessMockSvr.URL}, - param: ProfileParam{}, - expected: "mockService/main.go:30.13,48.33 13 1", - }, - { - name: "valid test with server flag provide", - service: ServiceUnderTest{Name: "serviceOK", Address: profileSuccessMockSvr.URL}, - param: ProfileParam{Service: []string{"serviceOK"}}, - expected: "mockService/main.go:30.13,48.33 13 1", - }, - { - name: "valid test with address flag provide", - service: ServiceUnderTest{Name: "serviceOK", Address: profileSuccessMockSvr.URL}, - param: ProfileParam{Address: []string{profileSuccessMockSvr.URL}}, - expected: "mockService/main.go:30.13,48.33 13 1", - }, - { - name: "invalid test with invalid server flag provide", - service: ServiceUnderTest{Name: "serviceOK", Address: profileSuccessMockSvr.URL}, - param: ProfileParam{Service: []string{"unknown"}}, - expected: "server [unknown] not found", - expectedErr: true, - }, - { - name: "invalid test with invalid profile got by server", - service: ServiceUnderTest{Name: "serviceErr", Address: profileErrMockSvr.URL}, - expected: "bad mode line: error", - expectedErr: true, - }, - { - name: "invalid test with disconnected server", - service: ServiceUnderTest{Name: "serviceNotExist", Address: "http://172.0.0.2:7777"}, - expected: "connection refused", - expectedErr: true, - }, - { - name: "invalid test with empty profile", - service: ServiceUnderTest{Name: "serviceNotExist", Address: "http://172.0.0.2:7777"}, - param: ProfileParam{Force: true}, - expectedErr: true, - expected: "no profiles", - }, - { - name: "valid test with coverfile flag provide", - service: ServiceUnderTest{Name: "serviceOK", Address: profileSuccessMockSvr.URL}, - param: ProfileParam{CoverFilePatterns: []string{"b.go$"}}, - expected: "b/b.go", - }, - { - name: "valid test with skipfile flag provided", - service: ServiceUnderTest{Name: "serviceOK", Address: profileSuccessMockSvr.URL}, - param: ProfileParam{SkipFilePatterns: []string{"b.go$"}}, - expected: "main.go", - }, - { - name: "valid test with both skipfile and coverfile flags provided", - service: ServiceUnderTest{Name: "serviceOK", Address: profileSuccessMockSvr.URL}, - param: ProfileParam{SkipFilePatterns: []string{"main.go"}, CoverFilePatterns: []string{".go$"}}, - expected: "b.go", - }, - } - for _, tc := range tcs { - t.Run(tc.name, func(t *testing.T) { - // init server - _, err = client.InitSystem() - assert.NoError(t, err) - // register server - res, err = client.RegisterService(tc.service) - assert.NoError(t, err) - assert.Contains(t, string(res), "success") - res, err = client.Profile(tc.param) - if err != nil { - if !tc.expectedErr { - t.Errorf("unexpected err got: %v", err) - } - return - } - - if tc.expectedErr { - t.Errorf("Expected an error, but got value %s", string(res)) - } - - assert.Regexp(t, tc.expected, string(res)) - }) - } - - // init system and check server again - _, err = client.InitSystem() - assert.NoError(t, err) - res, err = client.ListServices() - assert.NoError(t, err) - assert.Equal(t, "{}", string(res)) -} - -func TestClientRegisterService(t *testing.T) { - c := &client{} - - // client register with empty address - testService1 := ServiceUnderTest{ - Address: "", - Name: "abc", - } - _, err := c.RegisterService(testService1) - assert.Contains(t, err.Error(), "empty url") - - // client register with empty name - testService2 := ServiceUnderTest{ - Address: "http://127.0.0.1:444", - Name: "", - } - _, err = c.RegisterService(testService2) - assert.EqualError(t, err, "invalid service name") -} - -func TestClientListServices(t *testing.T) { - c := &client{ - Host: "http://127.0.0.1:64445", // a invalid host - client: http.DefaultClient, - } - _, err := c.ListServices() - assert.Contains(t, err.Error(), "connect: connection refused") -} - -func TestClientDo(t *testing.T) { - c := &client{ - client: http.DefaultClient, - } - _, _, err := c.do(" ", "http://127.0.0.1:7777", "", nil) // a invalid method - assert.Contains(t, err.Error(), "invalid method") -} - -func TestClientClearWithInvalidParam(t *testing.T) { - p := ProfileParam{ - Service: []string{"goc"}, - Address: []string{"http://127.0.0.1:777"}, - } - c := &client{ - client: http.DefaultClient, - } - _, err := c.Clear(p) - assert.Error(t, err) - assert.Contains(t, err.Error(), "use 'service' flag and 'address' flag at the same time may cause ambiguity, please use them separately") -} - -func TestClientRemove(t *testing.T) { - // remove by invalid param - p := ProfileParam{ - Service: []string{"goc"}, - Address: []string{"http://127.0.0.1:777"}, - } - c := &client{ - client: http.DefaultClient, - } - _, err := c.Remove(p) - assert.Error(t, err) - assert.Contains(t, err.Error(), "use 'service' flag and 'address' flag at the same time may cause ambiguity, please use them separately") - - // remove by valid param - ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - fmt.Fprintln(w, "Hello, client") - })) - defer ts.Close() - - c.Host = ts.URL - p = ProfileParam{ - Address: []string{"http://127.0.0.1:777"}, - } - res, err := c.Remove(p) - assert.NoError(t, err) - assert.Equal(t, string(res), "Hello, client\n") - - // remove from a invalid center - c.Host = "http://127.0.0.1:11111" - _, err = c.Remove(p) - assert.Error(t, err) -} diff --git a/pkg/cover/cover.go b/pkg/cover/cover.go index 742e352..1c4d149 100644 --- a/pkg/cover/cover.go +++ b/pkg/cover/cover.go @@ -1,346 +1,17 @@ -/* - Copyright 2020 Qiniu Cloud (qiniu.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 cover import ( - "bufio" - "bytes" "crypto/sha256" - "encoding/json" - "errors" "fmt" - "io" - "io/ioutil" - "os" - "os/exec" "path" - "path/filepath" - "sort" - "strconv" - "strings" - "time" - log "github.com/sirupsen/logrus" - - "github.com/qiniu/goc/pkg/cover/internal/tool" - "github.com/sirupsen/logrus" + "github.com/qiniu/goc/v2/pkg/config" ) -var ( - // ErrCoverPkgFailed represents the error that fails to inject the package - ErrCoverPkgFailed = errors.New("fail to inject code to project") - // ErrCoverListFailed represents the error that fails to list package dependencies - ErrCoverListFailed = errors.New("fail to list package dependencies") -) - -// TestCover is a collection of all counters -type TestCover struct { - Mode string - AgentPort string - Center string // cover profile host center - MainPkgCover *PackageCover - DepsCover []*PackageCover - CacheCover map[string]*PackageCover - GlobalCoverVarImportPath string -} - -// PackageCover holds all the generate coverage variables of a package -type PackageCover struct { - Package *Package - Vars map[string]*FileVar -} - -// FileVar holds the name of the generated coverage variables targeting the named file. -type FileVar struct { - File string - Var string -} - -// Package map a package output by go list -// this is subset of package struct in: https://github.com/golang/go/blob/master/src/cmd/go/internal/load/pkg.go#L58 -type Package struct { - Dir string `json:"Dir"` // directory containing package sources - ImportPath string `json:"ImportPath"` // import path of package in dir - Name string `json:"Name"` // package name - Target string `json:",omitempty"` // installed target for this package (may be executable) - Root string `json:",omitempty"` // Go root, Go path dir, or module root dir containing this package - - Module *ModulePublic `json:",omitempty"` // info about package's module, if any - Goroot bool `json:"Goroot,omitempty"` // is this package in the Go root? - Standard bool `json:"Standard,omitempty"` // is this package part of the standard Go library? - DepOnly bool `json:"DepOnly,omitempty"` // package is only a dependency, not explicitly listed - - // Source files - GoFiles []string `json:"GoFiles,omitempty"` // .go source files (excluding CgoFiles, TestGoFiles, XTestGoFiles) - CgoFiles []string `json:"CgoFiles,omitempty"` // .go source files that import "C" - - // Dependency information - Deps []string `json:"Deps,omitempty"` // all (recursively) imported dependencies - Imports []string `json:",omitempty"` // import paths used by this package - ImportMap map[string]string `json:",omitempty"` // map from source import to ImportPath (identity entries omitted) - - // Error information - Incomplete bool `json:"Incomplete,omitempty"` // this package or a dependency has an error - Error *PackageError `json:"Error,omitempty"` // error loading package - DepsErrors []*PackageError `json:"DepsErrors,omitempty"` // errors loading dependencies -} - -// ModulePublic represents the package info of a module -type ModulePublic struct { - Path string `json:",omitempty"` // module path - Version string `json:",omitempty"` // module version - Versions []string `json:",omitempty"` // available module versions - Replace *ModulePublic `json:",omitempty"` // replaced by this module - Time *time.Time `json:",omitempty"` // time version was created - Update *ModulePublic `json:",omitempty"` // available update (with -u) - Main bool `json:",omitempty"` // is this the main module? - Indirect bool `json:",omitempty"` // module is only indirectly needed by main module - Dir string `json:",omitempty"` // directory holding local copy of files, if any - GoMod string `json:",omitempty"` // path to go.mod file describing module, if any - GoVersion string `json:",omitempty"` // go version used in module - Error *ModuleError `json:",omitempty"` // error loading module -} - -// ModuleError represents the error loading module -type ModuleError struct { - Err string // error text -} - -// PackageError is the error info for a package when list failed -type PackageError struct { - ImportStack []string // shortest path from package named on command line to this one - Pos string // position of error (if present, file:line:col) - Err string // the error itself -} - -// CoverBuildInfo retreives some info from build -type CoverInfo struct { - Target string - GoPath string - IsMod bool - ModRootPath string - GlobalCoverVarImportPath string // path for the injected global cover var file - OneMainPackage bool - Args string - Mode string - AgentPort string - Center string -} - -//Execute inject cover variables for all the .go files in the target folder -func Execute(coverInfo *CoverInfo) error { - target := coverInfo.Target - newGopath := coverInfo.GoPath - // oneMainPackage := coverInfo.OneMainPackage - args := coverInfo.Args - mode := coverInfo.Mode - agentPort := coverInfo.AgentPort - center := coverInfo.Center - globalCoverVarImportPath := coverInfo.GlobalCoverVarImportPath - - if coverInfo.IsMod { - globalCoverVarImportPath = filepath.Join(coverInfo.ModRootPath, globalCoverVarImportPath) - } else { - globalCoverVarImportPath = filepath.Base(globalCoverVarImportPath) - } - - if !isDirExist(target) { - log.Errorf("Target directory %s not exist", target) - return ErrCoverPkgFailed - } - listArgs := []string{"-json"} - if len(args) != 0 { - listArgs = append(listArgs, args) - } - listArgs = append(listArgs, "./...") - pkgs, err := ListPackages(target, strings.Join(listArgs, " "), newGopath) - if err != nil { - log.Errorf("Fail to list all packages, the error: %v", err) - return err - } - - var seen = make(map[string]*PackageCover) - // var seenCache = make(map[string]*PackageCover) - allDecl := "" - for _, pkg := range pkgs { - if pkg.Name == "main" { - log.Printf("handle package: %v", pkg.ImportPath) - // inject the main package - mainCover, mainDecl := AddCounters(pkg, mode, globalCoverVarImportPath) - allDecl += mainDecl - // new a testcover for this service - tc := TestCover{ - Mode: mode, - AgentPort: agentPort, - Center: center, - MainPkgCover: mainCover, - GlobalCoverVarImportPath: globalCoverVarImportPath, - } - - // handle its dependency - // var internalPkgCache = make(map[string][]*PackageCover) - tc.CacheCover = make(map[string]*PackageCover) - for _, dep := range pkg.Deps { - if packageCover, ok := seen[dep]; ok { - tc.DepsCover = append(tc.DepsCover, packageCover) - continue - } - - //only focus package neither standard Go library nor dependency library - if depPkg, ok := pkgs[dep]; ok { - packageCover, depDecl := AddCounters(depPkg, mode, globalCoverVarImportPath) - allDecl += depDecl - tc.DepsCover = append(tc.DepsCover, packageCover) - seen[dep] = packageCover - } - } - - // inject Http Cover APIs - var httpCoverApis = fmt.Sprintf("%s/http_cover_apis_auto_generated.go", pkg.Dir) - if err := InjectCountersHandlers(tc, httpCoverApis); err != nil { - log.Errorf("failed to inject counters for package: %s, err: %v", pkg.ImportPath, err) - return ErrCoverPkgFailed - } - } - } - - return injectGlobalCoverVarFile(coverInfo, allDecl) -} - -// ListPackages list all packages under specific via go list command -// The argument newgopath is if you need to go list in a different GOPATH -func ListPackages(dir string, args string, newgopath string) (map[string]*Package, error) { - cmd := exec.Command("/bin/bash", "-c", "go list "+args) - log.Printf("go list cmd is: %v", cmd.Args) - cmd.Dir = dir - if newgopath != "" { - cmd.Env = append(os.Environ(), fmt.Sprintf("GOPATH=%v", newgopath)) - } - var errbuf bytes.Buffer - cmd.Stderr = &errbuf - out, err := cmd.Output() - if err != nil { - log.Errorf("excute `go list -json ./...` command failed, err: %v, stdout: %v, stderr: %v", err, string(out), errbuf.String()) - return nil, ErrCoverListFailed - } - log.Infof("\n%v", errbuf.String()) - dec := json.NewDecoder(bytes.NewReader(out)) - pkgs := make(map[string]*Package, 0) - for { - var pkg Package - if err := dec.Decode(&pkg); err != nil { - if err == io.EOF { - break - } - log.Errorf("reading go list output: %v", err) - return nil, ErrCoverListFailed - } - if pkg.Error != nil { - log.Errorf("list package %s failed with output: %v", pkg.ImportPath, pkg.Error) - return nil, ErrCoverPkgFailed - } - - // for _, err := range pkg.DepsErrors { - // log.Fatalf("dependency package list failed, err: %v", err) - // } - - pkgs[pkg.ImportPath] = &pkg - } - return pkgs, nil -} - -// AddCounters is different from official go tool cover -// 1. only inject covervar++ into source file -// 2. no declarartions for these covervars -// 3. return the declarations as string -func AddCounters(pkg *Package, mode string, globalCoverVarImportPath string) (*PackageCover, string) { - coverVarMap := declareCoverVars(pkg) - - decl := "" - for file, coverVar := range coverVarMap { - decl += "\n" + tool.Annotate(path.Join(pkg.Dir, file), mode, coverVar.Var, globalCoverVarImportPath) + "\n" - } - - return &PackageCover{ - Package: pkg, - Vars: coverVarMap, - }, decl -} - -func isDirExist(path string) bool { - s, err := os.Stat(path) - if err != nil { - return false - } - return s.IsDir() -} - -// Refer: https://github.com/golang/go/blob/master/src/cmd/go/internal/load/pkg.go#L1334:6 -// hasInternalPath looks for the final "internal" path element in the given import path. -// If there isn't one, hasInternalPath returns ok=false. -// Otherwise, hasInternalPath returns ok=true and the index of the "internal". -func hasInternalPath(path string) bool { - // Three cases, depending on internal at start/end of string or not. - // The order matters: we must return the index of the final element, - // because the final one produces the most restrictive requirement - // on the importer. - switch { - case strings.HasSuffix(path, "/internal"): - return true - case strings.Contains(path, "/internal/"): - return true - case path == "internal", strings.HasPrefix(path, "internal/"): - return true - } - return false -} - -func getInternalParent(path string) string { - switch { - case strings.HasSuffix(path, "/internal"): - return strings.Split(path, "/internal")[0] - case strings.Contains(path, "/internal/"): - return strings.Split(path, "/internal/")[0] - case path == "internal": - return "" - case strings.HasPrefix(path, "internal/"): - return strings.Split(path, "internal/")[0] - } - return "" -} - -func buildCoverCmd(file string, coverVar *FileVar, pkg *Package, mode, newgopath string) *exec.Cmd { - // to construct: go tool cover -mode=atomic -o dest src (note: dest==src) - var newArgs = []string{"tool", "cover"} - newArgs = append(newArgs, "-mode", mode) - newArgs = append(newArgs, "-var", coverVar.Var) - longPath := path.Join(pkg.Dir, file) - newArgs = append(newArgs, "-o", longPath, longPath) - cmd := exec.Command("go", newArgs...) - if newgopath != "" { - cmd.Env = append(os.Environ(), fmt.Sprintf("GOPATH=%v", newgopath)) - } - return cmd -} - // declareCoverVars attaches the required cover variables names // to the files, to be used when annotating the files. -func declareCoverVars(p *Package) map[string]*FileVar { - coverVars := make(map[string]*FileVar) +func declareCoverVars(p *config.Package) map[string]*config.FileVar { + coverVars := make(map[string]*config.FileVar) coverIndex := 0 // We create the cover counters as new top-level variables in the package. // We need to avoid collisions with user variables (GoCover_0 is unlikely but still) @@ -353,7 +24,7 @@ func declareCoverVars(p *Package) map[string]*FileVar { for _, file := range p.GoFiles { // These names appear in the cmd/cover HTML interface. var longFile = path.Join(p.ImportPath, file) - coverVars[file] = &FileVar{ + coverVars[file] = &config.FileVar{ File: longFile, Var: fmt.Sprintf("GoCover_%d_%x", coverIndex, h), } @@ -363,7 +34,7 @@ func declareCoverVars(p *Package) map[string]*FileVar { for _, file := range p.CgoFiles { // These names appear in the cmd/cover HTML interface. var longFile = path.Join(p.ImportPath, file) - coverVars[file] = &FileVar{ + coverVars[file] = &config.FileVar{ File: longFile, Var: fmt.Sprintf("GoCover_%d_%x", coverIndex, h), } @@ -372,203 +43,3 @@ func declareCoverVars(p *Package) map[string]*FileVar { return coverVars } - -func declareCacheVars(in *PackageCover) map[string]*FileVar { - sum := sha256.Sum256([]byte(in.Package.ImportPath)) - h := fmt.Sprintf("%x", sum[:5]) - - vars := make(map[string]*FileVar) - coverIndex := 0 - for _, v := range in.Vars { - cacheVar := fmt.Sprintf("GoCacheCover_%d_%x", coverIndex, h) - vars[cacheVar] = v - coverIndex++ - } - return vars -} - -func cacheInternalCover(in *PackageCover) *PackageCover { - c := &PackageCover{} - vars := declareCacheVars(in) - c.Package = in.Package - c.Vars = vars - return c -} - -func addCacheCover(pkg *Package, in *PackageCover) *PackageCover { - c := &PackageCover{} - sum := sha256.Sum256([]byte(pkg.ImportPath)) - h := fmt.Sprintf("%x", sum[:6]) - goFile := fmt.Sprintf("cache_vars_auto_generated_%x.go", h) - p := &Package{ - Dir: fmt.Sprintf("%s/cache_%x", pkg.Dir, h), - ImportPath: fmt.Sprintf("%s/cache_%x", pkg.ImportPath, h), - Name: fmt.Sprintf("cache_%x", h), - } - p.GoFiles = append(p.GoFiles, goFile) - c.Package = p - c.Vars = declareCacheVars(in) - return c -} - -// CoverageList is a collection and summary over multiple file Coverage objects -type CoverageList []Coverage - -// Coverage stores test coverage summary data for one file -type Coverage struct { - FileName string - NCoveredStmts int - NAllStmts int - LineCovLink string -} - -type codeBlock struct { - fileName string // the file the code block is in - numStatements int // number of statements in the code block - coverageCount int // number of times the block is covered -} - -// CovList converts profile to CoverageList struct -func CovList(f io.Reader) (g CoverageList, err error) { - scanner := bufio.NewScanner(f) - scanner.Scan() // discard first line - g = NewCoverageList() - - for scanner.Scan() { - row := scanner.Text() - blk, err := toBlock(row) - if err != nil { - return nil, err - } - blk.addToGroupCov(&g) - } - return -} - -// ReadFileToCoverList coverts profile file to CoverageList struct -func ReadFileToCoverList(path string) (g CoverageList, err error) { - f, err := ioutil.ReadFile(path) - if err != nil { - logrus.Errorf("Open file %s failed!", path) - return nil, err - } - g, err = CovList(bytes.NewReader(f)) - return -} - -// NewCoverageList return empty CoverageList -func NewCoverageList() CoverageList { - return CoverageList{} - -} - -func newCoverage(name string) *Coverage { - return &Coverage{name, 0, 0, ""} -} - -// convert a line in profile file to a codeBlock struct -func toBlock(line string) (res *codeBlock, err error) { - slice := strings.Split(line, " ") - if len(slice) != 3 { - return nil, fmt.Errorf("the profile line %s is not expected", line) - } - blockName := slice[0] - nStmts, _ := strconv.Atoi(slice[1]) - coverageCount, _ := strconv.Atoi(slice[2]) - return &codeBlock{ - fileName: blockName[:strings.Index(blockName, ":")], - numStatements: nStmts, - coverageCount: coverageCount, - }, nil -} - -// add blk Coverage to file group Coverage -func (blk *codeBlock) addToGroupCov(g *CoverageList) { - if g.size() == 0 || g.lastElement().Name() != blk.fileName { - // when a new file name is processed - coverage := newCoverage(blk.fileName) - g.append(coverage) - } - cov := g.lastElement() - cov.NAllStmts += blk.numStatements - if blk.coverageCount > 0 { - cov.NCoveredStmts += blk.numStatements - } -} - -func (g CoverageList) size() int { - return len(g) -} - -func (g CoverageList) lastElement() *Coverage { - return &g[g.size()-1] -} - -func (g *CoverageList) append(c *Coverage) { - *g = append(*g, *c) -} - -// Sort sorts CoverageList with filenames -func (g CoverageList) Sort() { - sort.SliceStable(g, func(i, j int) bool { - return g[i].Name() < g[j].Name() - }) -} - -// TotalPercentage returns the total percentage of coverage -func (g CoverageList) TotalPercentage() string { - ratio, err := g.TotalRatio() - if err == nil { - return PercentStr(ratio) - } - return "N/A" -} - -// TotalRatio returns the total ratio of covered statements -func (g CoverageList) TotalRatio() (ratio float32, err error) { - var total Coverage - for _, c := range g { - total.NCoveredStmts += c.NCoveredStmts - total.NAllStmts += c.NAllStmts - } - return total.Ratio() -} - -// Map returns maps the file name to its coverage for faster retrieval -// & membership check -func (g CoverageList) Map() map[string]Coverage { - m := make(map[string]Coverage) - for _, c := range g { - m[c.Name()] = c - } - return m -} - -// Name returns the file name -func (c *Coverage) Name() string { - return c.FileName -} - -// Percentage returns the percentage of statements covered -func (c *Coverage) Percentage() string { - ratio, err := c.Ratio() - if err == nil { - return PercentStr(ratio) - } - return "N/A" -} - -// Ratio calculates the ratio of statements in a profile -func (c *Coverage) Ratio() (ratio float32, err error) { - if c.NAllStmts == 0 { - err = fmt.Errorf("[%s] has 0 statement", c.Name()) - } else { - ratio = float32(c.NCoveredStmts) / float32(c.NAllStmts) - } - return -} - -// PercentStr converts a fraction number to percentage string representation -func PercentStr(f float32) string { - return fmt.Sprintf("%.1f%%", f*100) -} diff --git a/pkg/cover/cover_test.go b/pkg/cover/cover_test.go deleted file mode 100644 index e48e048..0000000 --- a/pkg/cover/cover_test.go +++ /dev/null @@ -1,388 +0,0 @@ -/* - Copyright 2020 Qiniu Cloud (qiniu.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 cover - -import ( - "fmt" - "os" - "os/exec" - "path/filepath" - "reflect" - "strings" - "testing" - - log "github.com/sirupsen/logrus" - - "github.com/stretchr/testify/assert" - "github.com/tongjingran/copy" -) - -func testCoverage() (c *Coverage) { - return &Coverage{FileName: "fake-coverage", NCoveredStmts: 200, NAllStmts: 300} -} - -func TestCoverageRatio(t *testing.T) { - c := testCoverage() - actualRatio, _ := c.Ratio() - assert.Equal(t, float32(c.NCoveredStmts)/float32(c.NAllStmts), actualRatio) -} - -func TestRatioErr(t *testing.T) { - c := &Coverage{FileName: "fake-coverage", NCoveredStmts: 200, NAllStmts: 0} - _, err := c.Ratio() - assert.NotEqual(t, err, nil) -} - -func TestPercentageNA(t *testing.T) { - c := &Coverage{FileName: "fake-coverage", NCoveredStmts: 200, NAllStmts: 0} - assert.Equal(t, "N/A", c.Percentage()) -} - -func TestCovList(t *testing.T) { - fileName := "qiniu.com/kodo/apiserver/server/main.go" - fileName1 := "qiniu.com/kodo/apiserver/server/svr.go" - - items := []struct { - profile string - expectPer []string - }{ - // percentage is 100% - { - profile: "mode: atomic\n" + - fileName + ":32.49,33.13 1 30\n", - expectPer: []string{"100.0%"}, - }, - // percentage is 50% - {profile: "mode: atomic\n" + - fileName + ":32.49,33.13 1 30\n" + - fileName + ":42.49,43.13 1 0\n", - expectPer: []string{"50.0%"}, - }, - // two files - { - profile: "mode: atomic\n" + - fileName + ":32.49,33.13 1 30\n" + - fileName1 + ":42.49,43.13 1 0\n", - expectPer: []string{"100.0%", "0.0%"}, - }, - } - - for _, tc := range items { - r := strings.NewReader(tc.profile) - c, err := CovList(r) - c.Sort() - assert.Equal(t, err, nil) - for k, v := range c { - assert.Equal(t, tc.expectPer[k], v.Percentage()) - } - } -} - -func TestReadFileToCoverList(t *testing.T) { - path := "unknown" - _, err := ReadFileToCoverList(path) - assert.Equal(t, err.Error(), "open unknown: no such file or directory") -} - -func TestTotalPercentage(t *testing.T) { - items := []struct { - list CoverageList - expectPer string - }{ - { - list: CoverageList{Coverage{FileName: "fake-coverage", NCoveredStmts: 15, NAllStmts: 0}}, - expectPer: "N/A", - }, - { - list: CoverageList{Coverage{FileName: "fake-coverage", NCoveredStmts: 15, NAllStmts: 20}}, - expectPer: "75.0%", - }, - { - list: CoverageList{Coverage{FileName: "fake-coverage", NCoveredStmts: 15, NAllStmts: 20}, - Coverage{FileName: "fake-coverage-1", NCoveredStmts: 10, NAllStmts: 30}}, - expectPer: "50.0%", - }, - } - - for _, tc := range items { - assert.Equal(t, tc.expectPer, tc.list.TotalPercentage()) - } -} - -func TestBuildCoverCmd(t *testing.T) { - var testCases = []struct { - name string - file string - coverVar *FileVar - pkg *Package - mode string - newgopath string - expectCmd *exec.Cmd - }{ - { - name: "normal", - file: "c.go", - coverVar: &FileVar{ - File: "example/b/c/c.go", - Var: "GoCover_0_643131623532653536333031", - }, - pkg: &Package{ - Dir: "/go/src/goc/cmd/example-project/b/c", - }, - mode: "count", - newgopath: "", - expectCmd: &exec.Cmd{ - Path: lookCmdPath("go"), - Args: []string{"go", "tool", "cover", "-mode", "count", "-var", "GoCover_0_643131623532653536333031", "-o", - "/go/src/goc/cmd/example-project/b/c/c.go", "/go/src/goc/cmd/example-project/b/c/c.go"}, - }, - }, - { - name: "normal with gopath", - file: "c.go", - coverVar: &FileVar{ - File: "example/b/c/c.go", - Var: "GoCover_0_643131623532653536333031", - }, - pkg: &Package{ - Dir: "/go/src/goc/cmd/example-project/b/c", - }, - mode: "set", - newgopath: "/go/src/goc", - expectCmd: &exec.Cmd{ - Path: lookCmdPath("go"), - Args: []string{"go", "tool", "cover", "-mode", "set", "-var", "GoCover_0_643131623532653536333031", "-o", - "/go/src/goc/cmd/example-project/b/c/c.go", "/go/src/goc/cmd/example-project/b/c/c.go"}, - Env: append(os.Environ(), fmt.Sprintf("GOPATH=%v", "/go/src/goc")), - }, - }, - } - for _, testCase := range testCases { - t.Run(testCase.name, func(t *testing.T) { - cmd := buildCoverCmd(testCase.file, testCase.coverVar, testCase.pkg, testCase.mode, testCase.newgopath) - if !reflect.DeepEqual(cmd, testCase.expectCmd) { - t.Errorf("generated incorrect commands:\nGot: %#v\nExpected:%#v", cmd, testCase.expectCmd) - } - }) - } - -} - -func lookCmdPath(name string) string { - if filepath.Base(name) == name { - if lp, err := exec.LookPath(name); err != nil { - log.Fatalf("find exec %s err: %v", name, err) - } else { - return lp - } - } - return "" -} - -func TestDeclareCoverVars(t *testing.T) { - var testCases = []struct { - name string - pkg *Package - expectCoverVar map[string]*FileVar - }{ - { - name: "normal", - pkg: &Package{ - Dir: "/go/src/goc/cmd/example-project/b/c", - GoFiles: []string{"c.go"}, - ImportPath: "example/b/c", - }, - expectCoverVar: map[string]*FileVar{ - "c.go": {File: "example/b/c/c.go", Var: "GoCover_0_643131623532653536333031"}, - }, - }, - { - name: "more go files", - pkg: &Package{ - Dir: "/go/src/goc/cmd/example-project/a/b", - GoFiles: []string{"printf.go", "printf1.go"}, - ImportPath: "example/a/b", - }, - expectCoverVar: map[string]*FileVar{ - "printf.go": {File: "example/a/b/printf.go", Var: "GoCover_0_326535623364613565313464"}, - "printf1.go": {File: "example/a/b/printf1.go", Var: "GoCover_1_326535623364613565313464"}, - }, - }, - } - for _, testCase := range testCases { - t.Run(testCase.name, func(t *testing.T) { - coverVar := declareCoverVars(testCase.pkg) - if !reflect.DeepEqual(coverVar, testCase.expectCoverVar) { - t.Errorf("generated incorrect cover vars:\nGot: %#v\nExpected:%#v", coverVar, testCase.expectCoverVar) - } - }) - } - -} - -func TestGetInternalParent(t *testing.T) { - var tcs = []struct { - ImportPath string - expectedParent string - }{ - { - ImportPath: "a/internal/b", - expectedParent: "a", - }, - { - ImportPath: "internal/b", - expectedParent: "", - }, - { - ImportPath: "a/b/internal/b", - expectedParent: "a/b", - }, - { - ImportPath: "a/b/internal", - expectedParent: "a/b", - }, - { - ImportPath: "a/b/internal/c", - expectedParent: "a/b", - }, - { - ImportPath: "a/b/c", - expectedParent: "", - }, - { - ImportPath: "", - expectedParent: "", - }, - } - - for _, tc := range tcs { - actual := getInternalParent(tc.ImportPath) - if actual != tc.expectedParent { - t.Errorf("getInternalParent failed for importPath %s, expected %s, got %s", tc.ImportPath, tc.expectedParent, actual) - } - } -} - -func TestFindInternal(t *testing.T) { - var tcs = []struct { - ImportPath string - expectedParent bool - }{ - { - ImportPath: "a/internal/b", - expectedParent: true, - }, - { - ImportPath: "internal/b", - expectedParent: true, - }, - { - ImportPath: "a/b/internal", - expectedParent: true, - }, - { - ImportPath: "a/b/c", - expectedParent: false, - }, - { - ImportPath: "internal", - expectedParent: true, - }, - } - - for _, tc := range tcs { - actual := hasInternalPath(tc.ImportPath) - if actual != tc.expectedParent { - t.Errorf("hasInternalPath check failed for importPath %s", tc.ImportPath) - } - } -} - -func TestExecuteForSimpleModProject(t *testing.T) { - workingDir := "../../tests/samples/simple_project" - gopath := "" - - os.Setenv("GOPATH", gopath) - os.Setenv("GO111MODULE", "on") - - testDir := filepath.Join(os.TempDir(), "goc-build-test") - copy.Copy(workingDir, testDir) - - bi := &CoverInfo{ - Args: "", - GoPath: gopath, - Target: testDir, - Mode: "count", - AgentPort: "", - Center: "http://127.0.0.1:7777", - OneMainPackage: false, - } - _ = Execute(bi) - - _, err := os.Lstat(filepath.Join(testDir, "http_cover_apis_auto_generated.go")) - if !assert.Equal(t, err, nil) { - assert.FailNow(t, "should generate http_cover_apis_auto_generated.go") - } -} - -func TestListPackagesForSimpleModProject(t *testing.T) { - workingDir := "../../tests/samples/simple_project" - gopath := "" - - os.Setenv("GOPATH", gopath) - os.Setenv("GO111MODULE", "on") - - pkgs, _ := ListPackages(workingDir, "-json ./...", "") - if !assert.Equal(t, len(pkgs), 1) { - assert.FailNow(t, "should only have one pkg") - } - if pkg, ok := pkgs["example.com/simple-project"]; ok { - assert.Equal(t, pkg.Module.Path, "example.com/simple-project") - } else { - assert.FailNow(t, "cannot get the pkg: example.com/simple-project") - } - -} - -// test if goc can get variables in internal package -func TestCoverResultForInternalPackage(t *testing.T) { - - workingDir := "../../tests/samples/simple_project_with_internal" - gopath := "" - - os.Setenv("GOPATH", gopath) - os.Setenv("GO111MODULE", "on") - - testDir := filepath.Join(os.TempDir(), "goc-build-test") - copy.Copy(workingDir, testDir) - - bi := &CoverInfo{ - Target: testDir, - GoPath: gopath, - Args: "", - Mode: "count", - Center: "http://127.0.0.1:7777", - OneMainPackage: false, - AgentPort: "", - } - _ = Execute(bi) - - _, err := os.Lstat(filepath.Join(testDir, "http_cover_apis_auto_generated.go")) - if !assert.Equal(t, err, nil) { - assert.FailNow(t, "should generate http_cover_apis_auto_generated.go") - } -} diff --git a/pkg/cover/delta.go b/pkg/cover/delta.go deleted file mode 100644 index 729f2c5..0000000 --- a/pkg/cover/delta.go +++ /dev/null @@ -1,136 +0,0 @@ -/* - Copyright 2020 Qiniu Cloud (qiniu.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 cover - -import "sort" - -// DeltaCov contains the info of a delta coverage -type DeltaCov struct { - FileName string - BasePer string - NewPer string - DeltaPer string - LineCovLink string -} - -// DeltaCovList is the list of DeltaCov -type DeltaCovList []DeltaCov - -// GetFullDeltaCov get full delta coverage between new and base profile -func GetFullDeltaCov(newList CoverageList, baseList CoverageList) (delta DeltaCovList) { - newMap := newList.Map() - baseMap := baseList.Map() - - for file, n := range newMap { - b, ok := baseMap[file] - //if the file not in base profile, set None - if !ok { - delta = append(delta, DeltaCov{ - FileName: file, - BasePer: "None", - NewPer: n.Percentage(), - DeltaPer: PercentStr(Delta(n, b))}) - continue - } - delta = append(delta, DeltaCov{ - FileName: file, - BasePer: b.Percentage(), - NewPer: n.Percentage(), - DeltaPer: PercentStr(Delta(n, b))}) - } - - for file, b := range baseMap { - //if the file not in new profile, set None - if n, ok := newMap[file]; !ok { - delta = append(delta, DeltaCov{ - FileName: file, - BasePer: b.Percentage(), - NewPer: "None", - DeltaPer: PercentStr(Delta(n, b))}) - } - } - return -} - -// GetDeltaCov get two profile diff cov -func GetDeltaCov(newList CoverageList, baseList CoverageList) (delta DeltaCovList) { - d := GetFullDeltaCov(newList, baseList) - for _, v := range d { - if v.DeltaPer == "0.0%" { - continue - } - delta = append(delta, v) - } - return -} - -// GetChFileDeltaCov get two profile diff cov of changed files -func GetChFileDeltaCov(newList CoverageList, baseList CoverageList, changedFiles []string) (list DeltaCovList) { - d := GetFullDeltaCov(newList, baseList) - dMap := d.Map() - for _, file := range changedFiles { - if _, ok := dMap[file]; ok { - list = append(list, dMap[file]) - } - } - return -} - -// Delta calculate two coverage delta -func Delta(new Coverage, base Coverage) float32 { - baseRatio, _ := base.Ratio() - newRatio, _ := new.Ratio() - return newRatio - baseRatio -} - -// TotalDelta calculate two coverage delta -func TotalDelta(new CoverageList, base CoverageList) float32 { - baseRatio, _ := base.TotalRatio() - newRatio, _ := new.TotalRatio() - return newRatio - baseRatio -} - -// Map returns maps the file name to its DeltaCov for faster retrieval & membership check -func (d DeltaCovList) Map() map[string]DeltaCov { - m := make(map[string]DeltaCov) - for _, c := range d { - m[c.FileName] = c - } - return m -} - -// Sort sort DeltaCovList with filenames -func (d DeltaCovList) Sort() { - sort.SliceStable(d, func(i, j int) bool { - return d[i].Name() < d[j].Name() - }) -} - -// Name returns the file name -func (c *DeltaCov) Name() string { - return c.FileName -} - -// GetLineCovLink get the LineCovLink of the DeltaCov -func (c *DeltaCov) GetLineCovLink() string { - return c.LineCovLink -} - -// SetLineCovLink set LineCovLink of the DeltaCov -func (c *DeltaCov) SetLineCovLink(link string) { - c.LineCovLink = link -} diff --git a/pkg/cover/delta_test.go b/pkg/cover/delta_test.go deleted file mode 100644 index 5982d5d..0000000 --- a/pkg/cover/delta_test.go +++ /dev/null @@ -1,133 +0,0 @@ -/* - Copyright 2020 Qiniu Cloud (qiniu.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 cover - -import ( - "testing" - - "github.com/stretchr/testify/assert" -) - -func TestGetDeltaCov(t *testing.T) { - items := []struct { - newList CoverageList - baseList CoverageList - expectDelta DeltaCovList - rows int - }{ - //coverage increase - { - newList: CoverageList{Coverage{FileName: "fake-coverage", NCoveredStmts: 15, NAllStmts: 20}}, - baseList: CoverageList{Coverage{FileName: "fake-coverage", NCoveredStmts: 10, NAllStmts: 20}}, - expectDelta: DeltaCovList{{FileName: "fake-coverage", BasePer: "50.0%", NewPer: "75.0%", DeltaPer: "25.0%"}}, - rows: 1, - }, - //coverage decrease - { - newList: CoverageList{Coverage{FileName: "fake-coverage", NCoveredStmts: 15, NAllStmts: 20}}, - baseList: CoverageList{Coverage{FileName: "fake-coverage", NCoveredStmts: 20, NAllStmts: 20}}, - expectDelta: DeltaCovList{{FileName: "fake-coverage", BasePer: "100.0%", NewPer: "75.0%", DeltaPer: "-25.0%"}}, - rows: 1, - }, - //diff file - { - newList: CoverageList{Coverage{FileName: "fake-coverage", NCoveredStmts: 15, NAllStmts: 20}}, - baseList: CoverageList{Coverage{FileName: "fake-coverage-v1", NCoveredStmts: 10, NAllStmts: 20}}, - expectDelta: DeltaCovList{{FileName: "fake-coverage", BasePer: "None", NewPer: "75.0%", DeltaPer: "75.0%"}, - {FileName: "fake-coverage-v1", BasePer: "50.0%", NewPer: "None", DeltaPer: "-50.0%"}}, - rows: 2, - }, - //one file has same coverage rate - { - newList: CoverageList{Coverage{FileName: "fake-coverage", NCoveredStmts: 15, NAllStmts: 20}}, - baseList: CoverageList{Coverage{FileName: "fake-coverage", NCoveredStmts: 15, NAllStmts: 20}, - Coverage{FileName: "fake-coverage-v1", NCoveredStmts: 10, NAllStmts: 20}}, - expectDelta: DeltaCovList{{FileName: "fake-coverage-v1", BasePer: "50.0%", NewPer: "None", DeltaPer: "-50.0%"}}, - rows: 1, - }, - } - - for _, tc := range items { - d := GetDeltaCov(tc.newList, tc.baseList) - assert.Equal(t, tc.rows, len(d)) - assert.Equal(t, tc.expectDelta, d) - } -} - -func TestGetChFileDeltaCov(t *testing.T) { - items := []struct { - newList CoverageList - baseList CoverageList - changedFiles []string - expectDelta DeltaCovList - }{ - { - newList: CoverageList{Coverage{FileName: "fake-coverage", NCoveredStmts: 15, NAllStmts: 20}}, - baseList: CoverageList{Coverage{FileName: "fake-coverage-v1", NCoveredStmts: 10, NAllStmts: 20}}, - changedFiles: []string{"fake-coverage"}, - expectDelta: DeltaCovList{{FileName: "fake-coverage", BasePer: "None", NewPer: "75.0%", DeltaPer: "75.0%"}}, - }, - } - for _, tc := range items { - d := GetChFileDeltaCov(tc.newList, tc.baseList, tc.changedFiles) - assert.Equal(t, tc.expectDelta, d) - } -} - -func TestMapAndSort(t *testing.T) { - items := []struct { - dList DeltaCovList - expectMap map[string]DeltaCov - expectSort DeltaCovList - }{ - { - dList: DeltaCovList{DeltaCov{FileName: "b", BasePer: "10.0%", NewPer: "20.0%", DeltaPer: "10.0%"}, - DeltaCov{FileName: "a", BasePer: "10.0%", NewPer: "30.0%", DeltaPer: "20.0%"}, - }, - expectMap: map[string]DeltaCov{ - "a": {FileName: "a", BasePer: "10.0%", NewPer: "30.0%", DeltaPer: "20.0%"}, - "b": {FileName: "b", BasePer: "10.0%", NewPer: "20.0%", DeltaPer: "10.0%"}, - }, - expectSort: DeltaCovList{DeltaCov{FileName: "a", BasePer: "10.0%", NewPer: "30.0%", DeltaPer: "20.0%"}, - DeltaCov{FileName: "b", BasePer: "10.0%", NewPer: "20.0%", DeltaPer: "10.0%"}, - }, - }, - { - dList: DeltaCovList{DeltaCov{FileName: "b", BasePer: "10.0%", NewPer: "20.0%", DeltaPer: "10.0%"}, - DeltaCov{FileName: "b-1", BasePer: "10.0%", NewPer: "30.0%", DeltaPer: "20.0%"}, - DeltaCov{FileName: "1-b", BasePer: "10.0%", NewPer: "40.0%", DeltaPer: "30.0%"}, - }, - expectMap: map[string]DeltaCov{ - "1-b": {FileName: "1-b", BasePer: "10.0%", NewPer: "40.0%", DeltaPer: "30.0%"}, - "b": {FileName: "b", BasePer: "10.0%", NewPer: "20.0%", DeltaPer: "10.0%"}, - "b-1": {FileName: "b-1", BasePer: "10.0%", NewPer: "30.0%", DeltaPer: "20.0%"}, - }, - expectSort: DeltaCovList{DeltaCov{FileName: "1-b", BasePer: "10.0%", NewPer: "40.0%", DeltaPer: "30.0%"}, - DeltaCov{FileName: "b", BasePer: "10.0%", NewPer: "20.0%", DeltaPer: "10.0%"}, - DeltaCov{FileName: "b-1", BasePer: "10.0%", NewPer: "30.0%", DeltaPer: "20.0%"}, - }, - }, - } - - for _, tc := range items { - assert.Equal(t, tc.expectMap, tc.dList.Map()) - tc.dList.Sort() - assert.Equal(t, tc.expectSort, tc.dList) - - } - -} diff --git a/pkg/cover/inject.go b/pkg/cover/inject.go new file mode 100644 index 0000000..1733936 --- /dev/null +++ b/pkg/cover/inject.go @@ -0,0 +1,236 @@ +package cover + +import ( + "os" + "path" + "path/filepath" + + "github.com/qiniu/goc/v2/pkg/config" + "github.com/qiniu/goc/v2/pkg/cover/internal/tool" + "github.com/qiniu/goc/v2/pkg/cover/internal/websocket" + "github.com/qiniu/goc/v2/pkg/log" +) + +// Inject injects cover variables for all the .go files in the target directory +func Inject() { + log.StartWait("injecting cover variables") + + var seen = make(map[string]*config.PackageCover) + + // 所有插桩变量定义声明 + allDecl := "" + + pkgs := config.GocConfig.Pkgs + for _, pkg := range pkgs { + if pkg.Name == "main" { + log.Infof("handle main package: %v", pkg.ImportPath) + // 该 main 二进制所关联的所有插桩变量的元信息 + // 每个 main 之间是不相关的,需要重新定义 + allMainCovers := make([]*config.PackageCover, 0) + // 注入 main package + mainCover, mainDecl := addCounters(pkg) + // 收集插桩变量的定义和元信息 + allDecl += mainDecl + allMainCovers = append(allMainCovers, mainCover) + + // 向 main package 的依赖注入插桩变量 + for _, dep := range pkg.Deps { + if _, ok := seen[dep]; ok { + continue + } + + // 依赖需要忽略 Go 标准库和 go.mod 引入的第三方 + if depPkg, ok := pkgs[dep]; ok { + // 注入依赖的 package + packageCover, depDecl := addCounters(depPkg) + // 收集插桩变量的定义和元信息 + allDecl += depDecl + allMainCovers = append(allMainCovers, packageCover) + // 避免重复访问 + seen[dep] = packageCover + } + } + // 为每个 main 包注入 websocket handler + injectGocAgent(getPkgTmpDir(pkg.Dir), allMainCovers) + } + } + // 在工程根目录注入所有插桩变量的声明+定义 + injectGlobalCoverVarFile(allDecl) + // 在工程根目录注入 watch agent 的定义 + if config.GocConfig.Mode == "watch" { + log.Infof("watch mode is enabled") + injectWatchAgentFile() + log.Donef("watch handler injected") + } + // 添加自定义 websocket 依赖 + // 用户代码可能有 gorrila/websocket 的依赖,为避免依赖冲突,以及可能的 replace/vendor, + // 这里直接注入一份完整的 gorrila/websocket 实现 + websocket.AddCustomWebsocketDep() + log.Donef("websocket library injected") + + log.StopWait() + log.Donef("cover variables injected") +} + +// addCounters is different from official go tool cover +// +// 1. only inject covervar++ into source file +// +// 2. no declarartions for these covervars +// +// 3. return the declarations as string +func addCounters(pkg *config.Package) (*config.PackageCover, string) { + mode := config.GocConfig.Mode + gobalCoverVarImportPath := config.GocConfig.GlobalCoverVarImportPath + + coverVarMap := declareCoverVars(pkg) + + decl := "" + for file, coverVar := range coverVarMap { + decl += "\n" + tool.Annotate(filepath.Join(getPkgTmpDir(pkg.Dir), file), mode, coverVar.Var, coverVar.File, gobalCoverVarImportPath) + "\n" + } + + return &config.PackageCover{ + Package: pkg, + Vars: coverVarMap, + }, decl +} + +// getPkgTmpDir gets corresponding pkg dir in temporary project +// +// the reason is that config.GocConfig.Pkgs is get in the original project. +// we need to transfer the direcory. +// +// 在原工程目录已经做了一次 go list -json,在临时目录没有必要再做一遍,直接转换一下就能得到 +// 临时目录中的 pkg.Dir。 +func getPkgTmpDir(pkgDir string) string { + relDir, err := filepath.Rel(config.GocConfig.CurModProjectDir, pkgDir) + if err != nil { + log.Fatalf("go json -list meta info wrong: %v", err) + } + + return filepath.Join(config.GocConfig.TmpModProjectDir, relDir) +} + +// injectGocAgent inject handlers like following +// +// - xxx.go +// - yyy_package +// - main.go +// - goc-cover-agent-apis-auto-generated-11111-22222-bridge.go +// - goc-cover-agent-apis-auto-generated-11111-22222-package +// | +// -- init.go +// +// 11111_22222_bridge.go 仅仅用于引用 11111_22222_package, where package contains ws agent main logic. +// 使用 bridge.go 文件是为了避免插桩逻辑中的变量名污染 main 包 +func injectGocAgent(where string, covers []*config.PackageCover) { + injectPkgName := "goc-cover-agent-apis-auto-generated-11111-22222-package" + injectBridgeName := "goc-cover-agent-apis-auto-generated-11111-22222-bridge.go" + wherePkg := filepath.Join(where, injectPkgName) + err := os.MkdirAll(wherePkg, os.ModePerm) + if err != nil { + log.Fatalf("fail to generate %v directory: %v", injectPkgName, err) + } + + // create bridge file + whereBridge := filepath.Join(where, injectBridgeName) + f1, err := os.Create(whereBridge) + if err != nil { + log.Fatalf("fail to create cover bridge file in temporary project: %v", err) + } + defer f1.Close() + + tmplBridgeData := struct { + CoverImportPath string + }{ + // covers[0] is the main package + CoverImportPath: covers[0].Package.ImportPath + "/" + injectPkgName, + } + + if err := coverBridgeTmpl.Execute(f1, tmplBridgeData); err != nil { + log.Fatalf("fail to generate cover bridge in temporary project: %v", err) + } + + // create ws agent files + dest := filepath.Join(wherePkg, "init.go") + + f2, err := os.Create(dest) + if err != nil { + log.Fatalf("fail to create cover agent file in temporary project: %v", err) + } + defer f2.Close() + + var _coverMode string + if config.GocConfig.Mode == "watch" { + _coverMode = "cover" + } else { + _coverMode = config.GocConfig.Mode + } + tmplData := struct { + Covers []*config.PackageCover + GlobalCoverVarImportPath string + Package string + Host string + Mode string + }{ + Covers: covers, + GlobalCoverVarImportPath: config.GocConfig.GlobalCoverVarImportPath, + Package: injectPkgName, + Host: config.GocConfig.Host, + Mode: _coverMode, + } + + if err := coverMainTmpl.Execute(f2, tmplData); err != nil { + log.Fatalf("fail to generate cover agent handlers in temporary project: %v", err) + } +} + +// injectGlobalCoverVarFile 写入所有插桩变量的全局定义至一个单独的文件 +func injectGlobalCoverVarFile(decl string) { + globalCoverVarPackage := path.Base(config.GocConfig.GlobalCoverVarImportPath) + globalCoverDef := filepath.Join(config.GocConfig.TmpModProjectDir, globalCoverVarPackage) + config.GocConfig.GlobalCoverVarImportPathDir = globalCoverDef + + err := os.MkdirAll(globalCoverDef, os.ModePerm) + if err != nil { + log.Fatalf("fail to create global cover definition package dir: %v", err) + } + coverFile, err := os.Create(filepath.Join(globalCoverDef, "cover.go")) + if err != nil { + log.Fatalf("fail to create global cover definition file: %v", err) + } + + defer coverFile.Close() + + packageName := "package coverdef\n\n" + + _, err = coverFile.WriteString(packageName + decl) + if err != nil { + log.Fatalf("fail to write to global cover definition file: %v", err) + } +} + +func injectWatchAgentFile() { + globalCoverVarPackage := path.Base(config.GocConfig.GlobalCoverVarImportPath) + globalCoverDef := filepath.Join(config.GocConfig.TmpModProjectDir, globalCoverVarPackage) + + f, err := os.Create(filepath.Join(globalCoverDef, "watchagent.go")) + if err != nil { + log.Fatalf("fail to create watchagent file: %v", err) + } + + tmplData := struct { + Random string + Host string + GlobalCoverVarImportPath string + }{ + Random: filepath.Base(config.GocConfig.TmpModProjectDir), + Host: config.GocConfig.Host, + GlobalCoverVarImportPath: config.GocConfig.GlobalCoverVarImportPath, + } + + if err := coverWatchTmpl.Execute(f, tmplData); err != nil { + log.Fatalf("fail to generate watchagent in temporary project: %v", err) + } +} diff --git a/pkg/cover/instrument.go b/pkg/cover/instrument.go deleted file mode 100644 index 4719e8f..0000000 --- a/pkg/cover/instrument.go +++ /dev/null @@ -1,505 +0,0 @@ -/* - Copyright 2020 Qiniu Cloud (qiniu.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 cover - -import ( - "fmt" - "os" - "path" - "path/filepath" - "text/template" -) - -// InjectCountersHandlers generate a file _cover_http_apis.go besides the main.go file -func InjectCountersHandlers(tc TestCover, dest string) error { - f, err := os.Create(dest) - if err != nil { - return err - } - if err := coverMainTmpl.Execute(f, tc); err != nil { - return err - } - return nil -} - -var coverMainTmpl = template.Must(template.New("coverMain").Parse(coverMain)) - -const coverMain = ` -// Code generated by goc system. DO NOT EDIT. - -package main - -import ( - "bufio" - "bytes" - "encoding/json" - "fmt" - "io" - "io/ioutil" - "log" - "net" - "net/http" - "os" - "os/signal" - "path/filepath" - "strings" - "sync/atomic" - "syscall" - "testing" - - _cover {{.GlobalCoverVarImportPath | printf "%q"}} - -) - -func init() { - go registerHandlers() -} - -func loadValues() (map[string][]uint32, map[string][]testing.CoverBlock) { - var ( - coverCounters = make(map[string][]uint32) - coverBlocks = make(map[string][]testing.CoverBlock) - ) - - {{range $i, $pkgCover := .DepsCover}} - {{range $file, $cover := $pkgCover.Vars}} - loadFileCover(coverCounters, coverBlocks, {{printf "%q" $cover.File}}, _cover.{{$cover.Var}}.Count[:], _cover.{{$cover.Var}}.Pos[:], _cover.{{$cover.Var}}.NumStmt[:]) - {{end}} - {{end}} - - {{range $file, $cover := .MainPkgCover.Vars}} - loadFileCover(coverCounters, coverBlocks, {{printf "%q" $cover.File}}, _cover.{{$cover.Var}}.Count[:], _cover.{{$cover.Var}}.Pos[:], _cover.{{$cover.Var}}.NumStmt[:]) - {{end}} - - return coverCounters, coverBlocks -} - -func loadFileCover(coverCounters map[string][]uint32, coverBlocks map[string][]testing.CoverBlock, fileName string, counter []uint32, pos []uint32, numStmts []uint16) { - if 3*len(counter) != len(pos) || len(counter) != len(numStmts) { - panic("coverage: mismatched sizes") - } - if coverCounters[fileName] != nil { - // Already registered. - return - } - coverCounters[fileName] = counter - block := make([]testing.CoverBlock, len(counter)) - for i := range counter { - block[i] = testing.CoverBlock{ - Line0: pos[3*i+0], - Col0: uint16(pos[3*i+2]), - Line1: pos[3*i+1], - Col1: uint16(pos[3*i+2] >> 16), - Stmts: numStmts[i], - } - } - coverBlocks[fileName] = block -} - -func clearValues() { - - {{range $i, $pkgCover := .DepsCover}} - {{range $file, $cover := $pkgCover.Vars}} - clearFileCover(_cover.{{$cover.Var}}.Count[:]) - {{end}} - {{end}} - - {{range $file, $cover := .MainPkgCover.Vars}} - clearFileCover(_cover.{{$cover.Var}}.Count[:]) - {{end}} - -} - -func clearFileCover(counter []uint32) { - for i := range counter { - counter[i] = 0 - } -} - -func registerHandlers() { - ln, host, err := listen() - if err != nil { - log.Fatalf("listen failed, err:%v", err) - } - - profileAddr := "http://" + host - if resp, err := registerSelf(profileAddr); err != nil { - log.Fatalf("register address %v failed, err: %v, response: %v", profileAddr, err, string(resp)) - } - - fn := func() { - var ( - err error - profileAddrs []string - addresses []string - ) - if addresses, err = getAllHosts(ln); err != nil { - log.Fatalf("get all host failed, err: %v", err) - return - } - for _, addr := range addresses { - profileAddrs = append(profileAddrs, "http://"+addr) - } - deregisterSelf(profileAddrs) - } - go watchSignal(fn) - - mux := http.NewServeMux() - // Coverage reports the current code coverage as a fraction in the range [0, 1]. - // If coverage is not enabled, Coverage returns 0. - mux.HandleFunc("/v1/cover/coverage", func(w http.ResponseWriter, r *http.Request) { - counters, _ := loadValues() - var n, d int64 - for _, counter := range counters { - for i := range counter { - if atomic.LoadUint32(&counter[i]) > 0 { - n++ - } - d++ - } - } - if d == 0 { - fmt.Fprint(w, 0) - return - } - fmt.Fprintf(w, "%f", float64(n)/float64(d)) - }) - - // coverprofile reports a coverage profile with the coverage percentage - mux.HandleFunc("/v1/cover/profile", func(w http.ResponseWriter, r *http.Request) { - fmt.Fprint(w, "mode: {{.Mode}}\n") - counters, blocks := loadValues() - var active, total int64 - var count uint32 - for name, counts := range counters { - block := blocks[name] - for i := range counts { - stmts := int64(block[i].Stmts) - total += stmts - count = atomic.LoadUint32(&counts[i]) // For -mode=atomic. - if count > 0 { - active += stmts - } - _, err := fmt.Fprintf(w, "%s:%d.%d,%d.%d %d %d\n", name, - block[i].Line0, block[i].Col0, - block[i].Line1, block[i].Col1, - stmts, - count) - if err != nil { - fmt.Fprintf(w, "invalid block format, err: %v", err) - return - } - } - } - }) - - mux.HandleFunc("/v1/cover/clear", func(w http.ResponseWriter, r *http.Request) { - clearValues() - w.WriteHeader(http.StatusOK) - fmt.Fprintln(w, "clear call successfully") - }) - - log.Fatal(http.Serve(ln, mux)) -} - -func registerSelf(address string) ([]byte, error) { - selfName := filepath.Base(os.Args[0]) - req, err := http.NewRequest("POST", fmt.Sprintf("%s/v1/cover/register?name=%s&address=%s", {{.Center | printf "%q"}}, selfName, address), nil) - if err != nil { - log.Fatalf("http.NewRequest failed: %v", err) - return nil, err - } - - resp, err := http.DefaultClient.Do(req) - if err != nil && isNetworkError(err) { - log.Printf("[goc][WARN]error occurred:%v, try again", err) - resp, err = http.DefaultClient.Do(req) - } - if err != nil { - return nil, fmt.Errorf("failed to register into coverage center, err:%v", err) - } - defer resp.Body.Close() - - body, err := ioutil.ReadAll(resp.Body) - if err != nil { - return nil, fmt.Errorf("failed to read response body, err:%v", err) - } - - if resp.StatusCode != 200 { - err = fmt.Errorf("failed to register into coverage center, response code %d", resp.StatusCode) - } - - return body, err -} - -func deregisterSelf(address []string) ([]byte, error) { - param := map[string]interface{}{ - "address": address, - } - jsonBody, err := json.Marshal(param) - if err != nil { - return nil, err - } - req, err := http.NewRequest("POST", fmt.Sprintf("%s/v1/cover/remove", {{.Center | printf "%q"}}), bytes.NewReader(jsonBody)) - if err != nil { - log.Fatalf("http.NewRequest failed: %v", err) - return nil, err - } - req.Header.Set("Content-Type", "application/json") - - resp, err := http.DefaultClient.Do(req) - if err != nil && isNetworkError(err) { - log.Printf("[goc][WARN]error occurred:%v, try again", err) - resp, err = http.DefaultClient.Do(req) - } - if err != nil { - return nil, fmt.Errorf("failed to deregister into coverage center, err:%v", err) - } - defer resp.Body.Close() - - body, err := ioutil.ReadAll(resp.Body) - if err != nil { - return nil, fmt.Errorf("failed to read response body, err:%v", err) - } - - if resp.StatusCode != 200 { - err = fmt.Errorf("failed to deregister into coverage center, response code %d", resp.StatusCode) - } - - return body, err -} - -type CallbackFunc func() - -func watchSignal(fn CallbackFunc) { - // init signal - c := make(chan os.Signal, 1) - signal.Notify(c, syscall.SIGHUP, syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGINT) - for { - si := <-c - log.Printf("get a signal %s", si.String()) - switch si { - case syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGINT: - fn() - os.Exit(0) // Exit successfully. - case syscall.SIGHUP: - default: - return - } - } -} - -func isNetworkError(err error) bool { - if err == io.EOF { - return true - } - _, ok := err.(net.Error) - return ok -} - -func listen() (ln net.Listener, host string, err error) { - agentPort := "{{.AgentPort }}" - if agentPort != "" { - if ln, err = net.Listen("tcp4", agentPort); err != nil { - return - } - if host, err = getRealHost(ln); err != nil { - return - } - } else { - // 获取上次使用的监听地址 - if previousAddr := getPreviousAddr(); previousAddr != "" { - ss := strings.Split(previousAddr, ":") - // listen on all network interface - ln, err = net.Listen("tcp4", ":"+ss[len(ss)-1]) - if err == nil { - host = previousAddr - return - } - } - if ln, err = net.Listen("tcp4", ":0"); err != nil { - return - } - if host, err = getRealHost(ln); err != nil { - return - } - } - go genProfileAddr(host) - return -} - -func getRealHost(ln net.Listener) (host string, err error) { - adds, err := net.InterfaceAddrs() - if err != nil { - return - } - - var localIPV4 string - var nonLocalIPV4 string - for _, addr := range adds { - if ipNet, ok := addr.(*net.IPNet); ok && ipNet.IP.To4() != nil { - if ipNet.IP.IsLoopback() { - localIPV4 = ipNet.IP.String() - } else { - nonLocalIPV4 = ipNet.IP.String() - } - } - } - if nonLocalIPV4 != "" { - host = fmt.Sprintf("%s:%d", nonLocalIPV4, ln.Addr().(*net.TCPAddr).Port) - } else { - host = fmt.Sprintf("%s:%d", localIPV4, ln.Addr().(*net.TCPAddr).Port) - } - - return -} - -func getAllHosts(ln net.Listener) (hosts []string, err error) { - adds, err := net.InterfaceAddrs() - if err != nil { - return - } - - var host string - for _, addr := range adds { - if ipNet, ok := addr.(*net.IPNet); ok && ipNet.IP.To4() != nil { - host = fmt.Sprintf("%s:%d", ipNet.IP.String(), ln.Addr().(*net.TCPAddr).Port) - hosts = append(hosts, host) - } - } - return -} - -func getPreviousAddr() string { - file, err := os.Open(os.Args[0] + "_profile_listen_addr") - if err != nil { - return "" - } - defer file.Close() - - reader := bufio.NewReader(file) - addr, _, _ := reader.ReadLine() - return string(addr) -} - -func genProfileAddr(profileAddr string) { - fn := os.Args[0] + "_profile_listen_addr" - f, err := os.OpenFile(fn, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0644) - if err != nil { - log.Println(err) - return - } - defer f.Close() - - fmt.Fprintf(f, strings.TrimPrefix(profileAddr, "http://")) -} -` - -var coverParentFileTmpl = template.Must(template.New("coverParentFileTmpl").Parse(coverParentFile)) - -const coverParentFile = ` -// Code generated by goc system. DO NOT EDIT. - -package {{.}} - -` - -var coverParentVarsTmpl = template.Must(template.New("coverParentVarsTmpl").Parse(coverParentVars)) - -const coverParentVars = ` - -import ( - - {{range $i, $pkgCover := .}} - _cover{{$i}} {{$pkgCover.Package.ImportPath | printf "%q"}} - {{end}} - -) - -{{range $i, $pkgCover := .}} -{{range $v, $cover := $pkgCover.Vars}} -var {{$v}} = &_cover{{$i}}.{{$cover.Var}} -{{end}} -{{end}} - -` - -func InjectCacheCounters(covers map[string][]*PackageCover, cache map[string]*PackageCover) []error { - var errs []error - for k, v := range covers { - if pkg, ok := cache[k]; ok { - err := checkCacheDir(pkg.Package.Dir) - if err != nil { - errs = append(errs, err) - continue - } - _, pkgName := path.Split(k) - err = injectCache(v, pkgName, fmt.Sprintf("%s/%s", pkg.Package.Dir, pkg.Package.GoFiles[0])) - if err != nil { - errs = append(errs, err) - continue - } - } - } - return errs -} - -// InjectCacheCounters generate a file _cover_http_apis.go besides the main.go file -func injectCache(covers []*PackageCover, pkg, dest string) error { - f, err := os.Create(dest) - if err != nil { - return err - } - - if err := coverParentFileTmpl.Execute(f, pkg); err != nil { - return err - } - - if err := coverParentVarsTmpl.Execute(f, covers); err != nil { - return err - } - return nil -} - -func checkCacheDir(p string) error { - _, err := os.Stat(p) - if os.IsNotExist(err) { - err := os.Mkdir(p, 0755) - if err != nil { - return err - } - } - return nil -} - -func injectGlobalCoverVarFile(ci *CoverInfo, content string) error { - coverFile, err := os.Create(filepath.Join(ci.Target, ci.GlobalCoverVarImportPath, "cover.go")) - if err != nil { - return err - } - defer coverFile.Close() - - packageName := "package " + filepath.Base(ci.GlobalCoverVarImportPath) + "\n\n" - - _, err = coverFile.WriteString(packageName) - if err != nil { - return err - } - _, err = coverFile.WriteString(content) - - return err -} diff --git a/pkg/cover/internal/tool/cover.go b/pkg/cover/internal/tool/cover.go index 283f535..fb2a93a 100644 --- a/pkg/cover/internal/tool/cover.go +++ b/pkg/cover/internal/tool/cover.go @@ -6,6 +6,8 @@ package tool import ( "bytes" + "path" + // "flag" "fmt" "go/ast" @@ -16,7 +18,7 @@ import ( "os" "sort" - log "github.com/sirupsen/logrus" // QINIU + "github.com/qiniu/goc/v2/pkg/log" // QINIU // "cmd/internal/edit" // "cmd/internal/objabi" ) @@ -155,14 +157,16 @@ type Block struct { // File is a wrapper for the state of a file used in the parser. // The basic parse tree walker is a method of this type. type File struct { - fset *token.FileSet - name string // Name of file. - astFile *ast.File - blocks []Block - content []byte - edit *Buffer // QINIU - varVar string // QINIU - mode string // QINIU + fset *token.FileSet + name string // Name of file. + astFile *ast.File + blocks []Block + content []byte + edit *Buffer // QINIU + varVar string // QINIU + mode string // QINIU + importpathFileName string // QINIU, importpath + filename + random string // QINIU, random == tmp dir name } // findText finds text in the original source, starting at pos. @@ -304,7 +308,7 @@ func (f *File) Visit(node ast.Node) ast.Visitor { // 1. add cover variables into the original file // 2. return the cover variables declarations as plain string // original dec: func annotate(name string) { -func Annotate(name string, mode string, varVar string, globalCoverVarImportPath string) string { +func Annotate(name string, mode string, varVar string, importpathFilename string, globalCoverVarImportPath string) string { // QINIU switch mode { case "set": @@ -313,6 +317,8 @@ func Annotate(name string, mode string, varVar string, globalCoverVarImportPath counterStmt = incCounterStmt case "atomic": counterStmt = atomicCounterStmt + case "watch": + counterStmt = watchCounterStmt default: counterStmt = incCounterStmt } @@ -328,20 +334,22 @@ func Annotate(name string, mode string, varVar string, globalCoverVarImportPath } file := &File{ - fset: fset, - name: name, - content: content, - edit: NewBuffer(content), // QINIU - astFile: parsedFile, - varVar: varVar, - mode: mode, + fset: fset, + name: name, + content: content, + edit: NewBuffer(content), // QINIU + astFile: parsedFile, + varVar: varVar, // QINIU + mode: mode, // QINIU + importpathFileName: importpathFilename, // QINIU + random: path.Base(globalCoverVarImportPath), // QINIU } ast.Walk(file, file.astFile) newContent := file.edit.Bytes() if bytes.Equal(content, newContent) { - log.Info("no cover var injected for: ", name) + log.Debugf("no cover var injected for: ", name) } else { // reback to the beginning file.astFile, _ = parser.ParseFile(fset, name, content, parser.ParseComments) @@ -409,6 +417,11 @@ func atomicCounterStmt(f *File, counter string) string { return fmt.Sprintf("%s.AddUint32(&%s, 1)", atomicPackageName, counter) } +// watchCounterStmt returns the expression: __count[23]++;UploadCoverChangeEvent(blockname, pos[:], index) +func watchCounterStmt(f *File, counter string) string { + return fmt.Sprintf("%s++; UploadCoverChangeEvent_%v(%s.BlockName, %s.Pos[:], %v)", counter, f.random, f.varVar, f.varVar, len(f.blocks)) +} + // QINIU // newCounter creates a new counter expression of the appropriate form. func (f *File) newCounter(start, end token.Pos, numStmt int) string { @@ -689,8 +702,12 @@ func (f *File) addVariables(w io.Writer) { fmt.Fprintf(w, "\tCount [%d]uint32\n", len(f.blocks)) fmt.Fprintf(w, "\tPos [3 * %d]uint32\n", len(f.blocks)) fmt.Fprintf(w, "\tNumStmt [%d]uint16\n", len(f.blocks)) + fmt.Fprintf(w, "\tBlockName string\n") // QINIU fmt.Fprintf(w, "} {\n") + // 写入 BlockName 初始化 + fmt.Fprintf(w, "\tBlockName: \"%v\",\n", f.importpathFileName) + // Initialize the position array field. fmt.Fprintf(w, "\tPos: [3 * %d]uint32{\n", len(f.blocks)) diff --git a/pkg/cover/internal/websocket/websocket.tar b/pkg/cover/internal/websocket/websocket.tar new file mode 100644 index 0000000..248f014 Binary files /dev/null and b/pkg/cover/internal/websocket/websocket.tar differ diff --git a/pkg/cover/internal/websocket/wsdep.go b/pkg/cover/internal/websocket/wsdep.go new file mode 100644 index 0000000..7176a39 --- /dev/null +++ b/pkg/cover/internal/websocket/wsdep.go @@ -0,0 +1,68 @@ +package websocket + +import ( + "archive/tar" + "bytes" + "embed" + "io" + "os" + "path/filepath" + + "github.com/qiniu/goc/v2/pkg/config" + "github.com/qiniu/goc/v2/pkg/log" +) + +//go:embed websocket.tar +var depTarFile embed.FS + +// AddCustomWebsocketDep injects custom gorrila/websocket library into the temporary directory +// +// 从 embed 文件系统中解压 websocket.tar 文件,并依次写入临时工程中,作为一个单独的包存在。 +// gorrila/websocket 是一个无第三方依赖的库,因此其位置可以随处移动,而不影响自身的编译。 +func AddCustomWebsocketDep() { + data, err := depTarFile.ReadFile("websocket.tar") + if err != nil { + log.Fatalf("cannot find the websocket.tar in the embed file: %v", err) + } + + buf := bytes.NewBuffer(data) + tr := tar.NewReader(buf) + for { + hdr, err := tr.Next() + if err == io.EOF { + break + } + if err != nil { + log.Fatalf("cannot untar the websocket.tar: %v", err) + } + + customWebsocketPath := config.GocConfig.GlobalCoverVarImportPathDir + fpath := filepath.Join(customWebsocketPath, hdr.Name) + if hdr.FileInfo().IsDir() { + // 处理目录 + err := os.MkdirAll(fpath, hdr.FileInfo().Mode()) + if err != nil { + log.Fatalf("fail to untar the websocket.tar: %v", err) + } + } else { + // 处理文件 + fdir := filepath.Dir(fpath) + err := os.MkdirAll(fdir, hdr.FileInfo().Mode()) + if err != nil { + log.Fatalf("fail to untar the websocket.tar: %v", err) + } + + f, err := os.OpenFile(fpath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, hdr.FileInfo().Mode()) + if err != nil { + log.Fatalf("fail to untar the websocket.tar: %v", err) + } + defer f.Close() + + _, err = io.Copy(f, tr) + + if err != nil { + log.Fatalf("fail to untar the websocket.tar: %v", err) + } + } + } +} diff --git a/pkg/cover/server.go b/pkg/cover/server.go deleted file mode 100644 index 9f058d1..0000000 --- a/pkg/cover/server.go +++ /dev/null @@ -1,394 +0,0 @@ -/* - Copyright 2020 Qiniu Cloud (qiniu.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 cover - -import ( - "bytes" - "fmt" - "io" - "io/ioutil" - "net" - "net/http" - "net/url" - "os" - "regexp" - - "github.com/gin-gonic/gin" - log "github.com/sirupsen/logrus" - "golang.org/x/tools/cover" - "k8s.io/test-infra/gopherage/pkg/cov" -) - -// LogFile a file to save log. -const LogFile = "goc.log" - -type server struct { - PersistenceFile string - Store Store -} - -// NewFileBasedServer new a file based server with persistenceFile -func NewFileBasedServer(persistenceFile string) (*server, error) { - store, err := NewFileStore(persistenceFile) - if err != nil { - return nil, err - } - return &server{ - PersistenceFile: persistenceFile, - Store: store, - }, nil -} - -// NewMemoryBasedServer new a memory based server without persistenceFile -func NewMemoryBasedServer() *server { - return &server{ - Store: NewMemoryStore(), - } -} - -// Run starts coverage host center -func (s *server) Run(port string) { - f, err := os.Create(LogFile) - if err != nil { - log.Fatalf("failed to create log file %s, err: %v", LogFile, err) - } - - // both log to stdout and file by default - mw := io.MultiWriter(f, os.Stdout) - r := s.Route(mw) - log.Fatal(r.Run(port)) -} - -// Router init goc server engine -func (s *server) Route(w io.Writer) *gin.Engine { - if w != nil { - gin.DefaultWriter = w - } - r := gin.Default() - // api to show the registered services - r.StaticFile("static", "./"+s.PersistenceFile) - - v1 := r.Group("/v1") - { - v1.POST("/cover/register", s.registerService) - v1.GET("/cover/profile", s.profile) - v1.POST("/cover/profile", s.profile) - v1.POST("/cover/clear", s.clear) - v1.POST("/cover/init", s.initSystem) - v1.GET("/cover/list", s.listServices) - v1.POST("/cover/remove", s.removeServices) - } - - return r -} - -// ServiceUnderTest is a entry under being tested -type ServiceUnderTest struct { - Name string `form:"name" json:"name" binding:"required"` - Address string `form:"address" json:"address" binding:"required"` -} - -// ProfileParam is param of profile API -type ProfileParam struct { - Force bool `form:"force" json:"force"` - Service []string `form:"service" json:"service"` - Address []string `form:"address" json:"address"` - CoverFilePatterns []string `form:"coverfile" json:"coverfile"` - SkipFilePatterns []string `form:"skipfile" json:"skipfile"` -} - -//listServices list all the registered services -func (s *server) listServices(c *gin.Context) { - services := s.Store.GetAll() - c.JSON(http.StatusOK, services) -} - -func (s *server) registerService(c *gin.Context) { - var service ServiceUnderTest - if err := c.ShouldBind(&service); err != nil { - c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) - return - } - - u, err := url.Parse(service.Address) - if err != nil { - c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) - return - } - host, port, err := net.SplitHostPort(u.Host) - if err != nil { - c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) - return - } - - realIP := c.ClientIP() - // only for IPV4 - // refer: https://github.com/qiniu/goc/issues/177 - if net.ParseIP(realIP).To4() != nil && host != realIP { - log.Printf("the registered host %s of service %s is different with the real one %s, here we choose the real one", service.Name, host, realIP) - service.Address = fmt.Sprintf("http://%s:%s", realIP, port) - } - - address := s.Store.Get(service.Name) - if !contains(address, service.Address) { - if err := s.Store.Add(service); err != nil && err != ErrServiceAlreadyRegistered { - c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) - return - } - } - - c.JSON(http.StatusOK, gin.H{"result": "success"}) - return -} - -// profile API examples: -// POST /v1/cover/profile -// { "force": "true", "service":["a","b"], "address":["c","d"],"coverfile":["e","f"] } -func (s *server) profile(c *gin.Context) { - var body ProfileParam - if err := c.ShouldBind(&body); err != nil { - c.JSON(http.StatusExpectationFailed, gin.H{"error": err.Error()}) - return - } - - allInfos := s.Store.GetAll() - filterAddrList, err := filterAddrs(body.Service, body.Address, body.Force, allInfos) - if err != nil { - c.JSON(http.StatusExpectationFailed, gin.H{"error": err.Error()}) - return - } - - var mergedProfiles = make([][]*cover.Profile, 0) - for _, addr := range filterAddrList { - pp, err := NewWorker(addr).Profile(ProfileParam{}) - if err != nil { - if body.Force { - log.Warnf("get profile from [%s] failed, error: %s", addr, err.Error()) - continue - } - - c.JSON(http.StatusExpectationFailed, gin.H{"error": fmt.Sprintf("failed to get profile from %s, error %s", addr, err.Error())}) - return - } - - profile, err := convertProfile(pp) - if err != nil { - c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) - return - } - mergedProfiles = append(mergedProfiles, profile) - } - - if len(mergedProfiles) == 0 { - c.JSON(http.StatusExpectationFailed, gin.H{"error": "no profiles"}) - return - } - - merged, err := cov.MergeMultipleProfiles(mergedProfiles) - if err != nil { - c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) - return - } - - if len(body.CoverFilePatterns) > 0 { - merged, err = filterProfile(body.CoverFilePatterns, merged) - if err != nil { - c.JSON(http.StatusInternalServerError, gin.H{"error": fmt.Sprintf("failed to filter profile based on the patterns: %v, error: %v", body.CoverFilePatterns, err)}) - return - } - } - - if len(body.SkipFilePatterns) > 0 { - merged, err = skipProfile(body.SkipFilePatterns, merged) - if err != nil { - c.JSON(http.StatusInternalServerError, gin.H{"error": fmt.Sprintf("failed to skip profile based on the patterns: %v, error: %v", body.SkipFilePatterns, err)}) - return - } - } - - if err := cov.DumpProfile(merged, c.Writer); err != nil { - c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) - return - } -} - -// filterProfile filters profiles of the packages matching the coverFile pattern -func filterProfile(coverFile []string, profiles []*cover.Profile) ([]*cover.Profile, error) { - var out = make([]*cover.Profile, 0) - for _, profile := range profiles { - for _, pattern := range coverFile { - matched, err := regexp.MatchString(pattern, profile.FileName) - if err != nil { - return nil, fmt.Errorf("filterProfile failed with pattern %s for profile %s, err: %v", pattern, profile.FileName, err) - } - if matched { - out = append(out, profile) - break // no need to check again for the file - } - } - } - - return out, nil -} - -// skipProfile skips profiles of the packages matching the skipFile pattern -func skipProfile(skipFile []string, profiles []*cover.Profile) ([]*cover.Profile, error) { - var out = make([]*cover.Profile, 0) - for _, profile := range profiles { - var shouldSkip bool - for _, pattern := range skipFile { - matched, err := regexp.MatchString(pattern, profile.FileName) - if err != nil { - return nil, fmt.Errorf("filterProfile failed with pattern %s for profile %s, err: %v", pattern, profile.FileName, err) - } - - if matched { - shouldSkip = true - break // no need to check again for the file - } - } - - if !shouldSkip { - out = append(out, profile) - } - } - - return out, nil -} - -func (s *server) clear(c *gin.Context) { - var body ProfileParam - if err := c.ShouldBind(&body); err != nil { - c.JSON(http.StatusExpectationFailed, gin.H{"error": err.Error()}) - return - } - svrsUnderTest := s.Store.GetAll() - filterAddrList, err := filterAddrs(body.Service, body.Address, true, svrsUnderTest) - if err != nil { - c.JSON(http.StatusExpectationFailed, gin.H{"error": err.Error()}) - return - } - for _, addr := range filterAddrList { - pp, err := NewWorker(addr).Clear(ProfileParam{}) - if err != nil { - c.JSON(http.StatusExpectationFailed, gin.H{"error": err.Error()}) - return - } - fmt.Fprintf(c.Writer, "Register service %s coverage counter %s", addr, string(pp)) - } - -} - -func (s *server) initSystem(c *gin.Context) { - if err := s.Store.Init(); err != nil { - c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) - return - } - - c.JSON(http.StatusOK, "") -} - -func (s *server) removeServices(c *gin.Context) { - var body ProfileParam - if err := c.ShouldBind(&body); err != nil { - c.JSON(http.StatusExpectationFailed, gin.H{"error": err.Error()}) - return - } - svrsUnderTest := s.Store.GetAll() - filterAddrList, err := filterAddrs(body.Service, body.Address, true, svrsUnderTest) - if err != nil { - c.JSON(http.StatusExpectationFailed, gin.H{"error": err.Error()}) - return - } - for _, addr := range filterAddrList { - err := s.Store.Remove(addr) - if err != nil { - c.JSON(http.StatusExpectationFailed, gin.H{"error": err.Error()}) - return - } - fmt.Fprintf(c.Writer, "Register service %s removed from the center.", addr) - } -} - -func convertProfile(p []byte) ([]*cover.Profile, error) { - // Annoyingly, ParseProfiles only accepts a filename, so we have to write the bytes to disk - // so it can read them back. - // We could probably also just give it /dev/stdin, but that'll break on Windows. - tf, err := ioutil.TempFile("", "") - if err != nil { - return nil, fmt.Errorf("failed to create temp file, err: %v", err) - } - defer tf.Close() - defer os.Remove(tf.Name()) - if _, err := io.Copy(tf, bytes.NewReader(p)); err != nil { - return nil, fmt.Errorf("failed to copy data to temp file, err: %v", err) - } - - return cover.ParseProfiles(tf.Name()) -} - -func contains(arr []string, str string) bool { - for _, element := range arr { - if str == element { - return true - } - } - return false -} - -// filterAddrs filter address list by given service and address list -func filterAddrs(serviceList, addressList []string, force bool, allInfos map[string][]string) (filterAddrList []string, err error) { - addressAll := []string{} - for _, addr := range allInfos { - addressAll = append(addressAll, addr...) - } - - if len(serviceList) != 0 && len(addressList) != 0 { - return nil, fmt.Errorf("use 'service' flag and 'address' flag at the same time may cause ambiguity, please use them separately") - } - - // Add matched services to map - for _, name := range serviceList { - if addr, ok := allInfos[name]; ok { - filterAddrList = append(filterAddrList, addr...) - continue // jump to match the next service - } - if !force { - return nil, fmt.Errorf("service [%s] not found", name) - } - log.Warnf("service [%s] not found", name) - } - - // Add matched addresses to map - for _, addr := range addressList { - if contains(addressAll, addr) { - filterAddrList = append(filterAddrList, addr) - continue - } - if !force { - return nil, fmt.Errorf("address [%s] not found", addr) - } - log.Warnf("address [%s] not found", addr) - } - - if len(addressList) == 0 && len(serviceList) == 0 { - filterAddrList = addressAll - } - - // Return all services when all param is nil - return filterAddrList, nil -} diff --git a/pkg/cover/server_test.go b/pkg/cover/server_test.go deleted file mode 100644 index 5ccbaaa..0000000 --- a/pkg/cover/server_test.go +++ /dev/null @@ -1,527 +0,0 @@ -package cover - -import ( - "bytes" - "encoding/json" - "fmt" - "net/http" - "net/http/httptest" - "net/url" - "os" - "reflect" - "strings" - "testing" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/mock" - "golang.org/x/tools/cover" -) - -// MockStore is mock store mainly for unittest -type MockStore struct { - mock.Mock -} - -func (m *MockStore) Add(s ServiceUnderTest) error { - args := m.Called(s) - return args.Error(0) -} - -func (m *MockStore) Remove(a string) error { - args := m.Called(a) - return args.Error(0) -} - -func (m *MockStore) Get(name string) []string { - args := m.Called(name) - return args.Get(0).([]string) -} - -func (m *MockStore) GetAll() map[string][]string { - args := m.Called() - return args.Get(0).(map[string][]string) -} - -func (m *MockStore) Init() error { - args := m.Called() - return args.Error(0) -} - -func (m *MockStore) Set(services map[string][]string) error { - args := m.Called() - return args.Error(0) -} - -func TestContains(t *testing.T) { - assert.Equal(t, contains([]string{"a", "b"}, "a"), true) - assert.Equal(t, contains([]string{"a", "b"}, "c"), false) -} - -func TestFilterAddrs(t *testing.T) { - svrAll := map[string][]string{ - "service1": {"http://127.0.0.1:7777", "http://127.0.0.1:8888"}, - "service2": {"http://127.0.0.1:9999"}, - } - addrAll := []string{} - for _, addr := range svrAll { - addrAll = append(addrAll, addr...) - } - items := []struct { - svrList []string - addrList []string - force bool - err string - addrRes []string - }{ - { - svrList: []string{"service1"}, - addrList: []string{"http://127.0.0.1:7777"}, - err: "use 'service' flag and 'address' flag at the same time may cause ambiguity, please use them separately", - }, - { - addrRes: addrAll, - }, - { - svrList: []string{"service1", "unknown"}, - err: "service [unknown] not found", - }, - { - svrList: []string{"service1", "service2", "unknown"}, - force: true, - addrRes: addrAll, - }, - { - svrList: []string{"unknown"}, - force: true, - }, - { - addrList: []string{"http://127.0.0.1:7777", "http://127.0.0.2:7777"}, - err: "address [http://127.0.0.2:7777] not found", - }, - { - addrList: []string{"http://127.0.0.1:7777", "http://127.0.0.1:9999", "http://127.0.0.2:7777"}, - force: true, - addrRes: []string{"http://127.0.0.1:7777", "http://127.0.0.1:9999"}, - }, - } - for _, item := range items { - addrs, err := filterAddrs(item.svrList, item.addrList, item.force, svrAll) - if err != nil { - assert.Equal(t, err.Error(), item.err) - } else { - if len(addrs) == 0 { - assert.Equal(t, addrs, item.addrRes) - } - for _, a := range addrs { - assert.Contains(t, item.addrRes, a) - } - } - } -} - -func TestRegisterService(t *testing.T) { - server, err := NewFileBasedServer("_svrs_address.txt") - assert.NoError(t, err) - router := server.Route(os.Stdout) - - // register with empty service struct - w := httptest.NewRecorder() - req, _ := http.NewRequest("POST", "/v1/cover/register", nil) - router.ServeHTTP(w, req) - - assert.Equal(t, http.StatusBadRequest, w.Code) - - // register with invalid service.Address - data := url.Values{} - data.Set("name", "aaa") - data.Set("address", "&%%") - w = httptest.NewRecorder() - req, _ = http.NewRequest("POST", "/v1/cover/register", strings.NewReader(data.Encode())) - req.Header.Set("Content-Type", "application/x-www-form-urlencoded") - router.ServeHTTP(w, req) - - assert.Equal(t, http.StatusBadRequest, w.Code) - assert.Contains(t, w.Body.String(), "invalid URL escape") - - // register with host but no port - data = url.Values{} - data.Set("name", "aaa") - data.Set("address", "http://127.0.0.1") - w = httptest.NewRecorder() - req, _ = http.NewRequest("POST", "/v1/cover/register", strings.NewReader(data.Encode())) - req.Header.Set("Content-Type", "application/x-www-form-urlencoded") - router.ServeHTTP(w, req) - - assert.Equal(t, http.StatusBadRequest, w.Code) - assert.Contains(t, w.Body.String(), "missing port in address") - - // register with store failure - expectedS := ServiceUnderTest{ - Name: "foo", - Address: "http://:64444", // the real IP is empty in unittest, so server will get a empty one - } - testObj := new(MockStore) - testObj.On("Get", "foo").Return([]string{"http://127.0.0.1:66666"}) - testObj.On("Add", expectedS).Return(fmt.Errorf("lala error")) - - server.Store = testObj - - w = httptest.NewRecorder() - data.Set("name", expectedS.Name) - data.Set("address", expectedS.Address) - req, _ = http.NewRequest("POST", "/v1/cover/register", strings.NewReader(data.Encode())) - req.Header.Set("Content-Type", "application/x-www-form-urlencoded") - router.ServeHTTP(w, req) - - assert.Equal(t, http.StatusInternalServerError, w.Code) - assert.Contains(t, w.Body.String(), "lala error") -} - -func TestProfileService(t *testing.T) { - server, err := NewFileBasedServer("_svrs_address.txt") - assert.NoError(t, err) - router := server.Route(os.Stdout) - - // get profile with invalid force parameter - w := httptest.NewRecorder() - req, _ := http.NewRequest("GET", "/v1/cover/profile?force=11", nil) - router.ServeHTTP(w, req) - - assert.Equal(t, http.StatusExpectationFailed, w.Code) - assert.Contains(t, w.Body.String(), "invalid syntax") -} - -func TestClearService(t *testing.T) { - testObj := new(MockStore) - testObj.On("GetAll").Return(map[string][]string{"foo": {"http://127.0.0.1:66666"}}) - - server := &server{ - Store: testObj, - } - router := server.Route(os.Stdout) - - // clear profile with non-exist port - w := httptest.NewRecorder() - req, _ := http.NewRequest("POST", "/v1/cover/clear", bytes.NewBuffer([]byte(`{}`))) - req.Header.Set("Content-Type", "application/json") - router.ServeHTTP(w, req) - - assert.Equal(t, http.StatusExpectationFailed, w.Code) - assert.Contains(t, w.Body.String(), "invalid port") - - // clear profile with invalid service - w = httptest.NewRecorder() - req, _ = http.NewRequest("POST", "/v1/cover/clear", nil) - req.Header.Set("Content-Type", "application/json") - router.ServeHTTP(w, req) - assert.Equal(t, http.StatusExpectationFailed, w.Code) - assert.Contains(t, w.Body.String(), "invalid request") - - // clear profile with service and address set at at the same time - p := ProfileParam{ - Service: []string{"goc"}, - Address: []string{"http://127.0.0.1:3333"}, - } - encoded, err := json.Marshal(p) - assert.NoError(t, err) - w = httptest.NewRecorder() - req, _ = http.NewRequest("POST", "/v1/cover/clear", bytes.NewBuffer(encoded)) - req.Header.Set("Content-Type", "application/json") - router.ServeHTTP(w, req) - assert.Equal(t, http.StatusExpectationFailed, w.Code) - assert.Contains(t, w.Body.String(), "use 'service' flag and 'address' flag at the same time may cause ambiguity, please use them separately") -} - -func TestRemoveServices(t *testing.T) { - testObj := new(MockStore) - testObj.On("GetAll").Return(map[string][]string{"foo": {"test1", "test2"}}) - testObj.On("Remove", "test1").Return(nil) - - server := &server{ - Store: testObj, - } - router := server.Route(os.Stdout) - - // remove with invalid request - w := httptest.NewRecorder() - req, _ := http.NewRequest("POST", "/v1/cover/remove", nil) - req.Header.Set("Content-Type", "application/json") - router.ServeHTTP(w, req) - - assert.Equal(t, http.StatusExpectationFailed, w.Code) - assert.Contains(t, w.Body.String(), "invalid request") - - // remove service - p := ProfileParam{ - Address: []string{"test1"}, - } - encoded, err := json.Marshal(p) - assert.NoError(t, err) - w = httptest.NewRecorder() - req, _ = http.NewRequest("POST", "/v1/cover/remove", bytes.NewBuffer(encoded)) - req.Header.Set("Content-Type", "application/json") - router.ServeHTTP(w, req) - - assert.Equal(t, http.StatusOK, w.Code) - assert.Contains(t, w.Body.String(), "Register service test1 removed from the center.") - - // remove service with non-exist address - testObj.On("Remove", "test2").Return(fmt.Errorf("no service found")) - p = ProfileParam{ - Address: []string{"test2"}, - } - encoded, err = json.Marshal(p) - assert.NoError(t, err) - w = httptest.NewRecorder() - req, _ = http.NewRequest("POST", "/v1/cover/remove", bytes.NewBuffer(encoded)) - req.Header.Set("Content-Type", "application/json") - router.ServeHTTP(w, req) - - assert.Equal(t, http.StatusExpectationFailed, w.Code) - assert.Contains(t, w.Body.String(), "no service found") - - // clear profile with service and address set at at the same time - p = ProfileParam{ - Service: []string{"goc"}, - Address: []string{"http://127.0.0.1:3333"}, - } - encoded, err = json.Marshal(p) - assert.NoError(t, err) - w = httptest.NewRecorder() - req, _ = http.NewRequest("POST", "/v1/cover/remove", bytes.NewBuffer(encoded)) - req.Header.Set("Content-Type", "application/json") - router.ServeHTTP(w, req) - assert.Equal(t, http.StatusExpectationFailed, w.Code) - assert.Contains(t, w.Body.String(), "use 'service' flag and 'address' flag at the same time may cause ambiguity, please use them separately") -} - -func TestInitService(t *testing.T) { - testObj := new(MockStore) - testObj.On("Init").Return(fmt.Errorf("lala error")) - - server := &server{ - Store: testObj, - } - router := server.Route(os.Stdout) - - // get profile with invalid force parameter - w := httptest.NewRecorder() - req, _ := http.NewRequest("POST", "/v1/cover/init", nil) - router.ServeHTTP(w, req) - - assert.Equal(t, http.StatusInternalServerError, w.Code) - assert.Contains(t, w.Body.String(), "lala error") -} - -func TestFilterProfile(t *testing.T) { - var tcs = []struct { - name string - pattern []string - input []*cover.Profile - output []*cover.Profile - expectErr bool - }{ - { - name: "normal path", - pattern: []string{"some/fancy/gopath", "a/fancy/gopath"}, - input: []*cover.Profile{ - { - FileName: "some/fancy/gopath/a.go", - }, - { - FileName: "some/fancy/gopath/b/a.go", - }, - { - FileName: "a/fancy/gopath/a.go", - }, - { - FileName: "b/fancy/gopath/a.go", - }, - { - FileName: "b/a/fancy/gopath/a.go", - }, - }, - output: []*cover.Profile{ - { - FileName: "some/fancy/gopath/a.go", - }, - { - FileName: "some/fancy/gopath/b/a.go", - }, - { - FileName: "a/fancy/gopath/a.go", - }, - { - FileName: "b/a/fancy/gopath/a.go", - }, - }, - }, - { - name: "with regular expression", - pattern: []string{"fancy/gopath/a.go$", "^b/a/"}, - input: []*cover.Profile{ - { - FileName: "some/fancy/gopath/a.go", - }, - { - FileName: "some/fancy/gopath/b/a.go", - }, - { - FileName: "a/fancy/gopath/a.go", - }, - { - FileName: "b/fancy/gopath/c/a.go", - }, - { - FileName: "b/a/fancy/gopath/a.go", - }, - }, - output: []*cover.Profile{ - { - FileName: "some/fancy/gopath/a.go", - }, - { - FileName: "a/fancy/gopath/a.go", - }, - { - FileName: "b/a/fancy/gopath/a.go", - }, - }, - }, - { - name: "with invalid regular expression", - pattern: []string{"(?!a)"}, - input: []*cover.Profile{ - { - FileName: "some/fancy/gopath/a.go", - }, - }, - expectErr: true, - }, - } - - for _, tc := range tcs { - t.Run(tc.name, func(t *testing.T) { - out, err := filterProfile(tc.pattern, tc.input) - if err != nil { - if !tc.expectErr { - t.Errorf("Unexpected error: %v", err) - } - return - } - - if tc.expectErr { - t.Errorf("Expected an error, but got value %s", stringifyCoverProfile(out)) - } - - if !reflect.DeepEqual(out, tc.output) { - t.Errorf("Mismatched results. \nExpected: %s\nActual:%s", stringifyCoverProfile(tc.output), stringifyCoverProfile(out)) - } - }) - } -} - -func TestSkipProfile(t *testing.T) { - var tcs = []struct { - name string - pattern []string - input []*cover.Profile - output []*cover.Profile - expectErr bool - }{ - { - name: "normal path", - pattern: []string{"some/fancy/gopath", "a/fancy/gopath"}, - input: []*cover.Profile{ - { - FileName: "some/fancy/gopath/a.go", - }, - { - FileName: "some/fancy/gopath/b/a.go", - }, - { - FileName: "a/fancy/gopath/a.go", - }, - { - FileName: "b/fancy/gopath/a.go", - }, - { - FileName: "b/a/fancy/gopath/a.go", - }, - }, - output: []*cover.Profile{ - { - FileName: "b/fancy/gopath/a.go", - }, - }, - }, - { - name: "with regular expression", - pattern: []string{"fancy/gopath/a.go$", "^b/a/"}, - input: []*cover.Profile{ - { - FileName: "some/fancy/gopath/a.go", - }, - { - FileName: "some/fancy/gopath/b/a.go", - }, - { - FileName: "a/fancy/gopath/a.go", - }, - { - FileName: "b/fancy/gopath/c/a.go", - }, - { - FileName: "b/a/fancy/gopath/a.go", - }, - }, - output: []*cover.Profile{ - { - FileName: "some/fancy/gopath/b/a.go", - }, - { - FileName: "b/fancy/gopath/c/a.go", - }, - }, - }, - { - name: "with invalid regular expression", - pattern: []string{"(?!a)"}, - input: []*cover.Profile{ - { - FileName: "some/fancy/gopath/a.go", - }, - }, - expectErr: true, - }, - } - - for _, tc := range tcs { - t.Run(tc.name, func(t *testing.T) { - out, err := skipProfile(tc.pattern, tc.input) - if err != nil { - if !tc.expectErr { - t.Errorf("Unexpected error: %v", err) - } - return - } - - if tc.expectErr { - t.Errorf("Expected an error, but got value %s", stringifyCoverProfile(out)) - } - - if !reflect.DeepEqual(out, tc.output) { - t.Errorf("Mismatched results. \nExpected: %s\nActual:%s", stringifyCoverProfile(tc.output), stringifyCoverProfile(out)) - } - }) - } -} - -func stringifyCoverProfile(profiles []*cover.Profile) string { - res := make([]cover.Profile, 0, len(profiles)) - for _, p := range profiles { - res = append(res, *p) - } - - return fmt.Sprintf("%#v", res) -} diff --git a/pkg/cover/store.go b/pkg/cover/store.go deleted file mode 100644 index 0929039..0000000 --- a/pkg/cover/store.go +++ /dev/null @@ -1,324 +0,0 @@ -/* - Copyright 2020 Qiniu Cloud (qiniu.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 cover - -import ( - "bufio" - "errors" - "fmt" - "os" - "path/filepath" - "strings" - "sync" - - log "github.com/sirupsen/logrus" -) - -var ErrServiceAlreadyRegistered = errors.New("service already registered") - -// Store persistents the registered service information -type Store interface { - // Add adds the given service to store - Add(s ServiceUnderTest) error - - // Get returns the registered service information with the given service's name - Get(name string) []string - - // Get returns all the registered service information as a map - GetAll() map[string][]string - - // Init cleanup all the registered service information - Init() error - - // Set stores the services information into internal state - Set(services map[string][]string) error - - // Remove the service from the store by address - Remove(addr string) error -} - -// fileStore holds the registered services into memory and persistent to a local file -type fileStore struct { - mu sync.RWMutex - persistentFile string - - memoryStore Store -} - -// NewFileStore creates a store using local file -func NewFileStore(persistenceFile string) (store Store, err error) { - path, err := filepath.Abs(persistenceFile) - if err != nil { - return nil, err - } - err = os.MkdirAll(filepath.Dir(path), os.ModePerm) - if err != nil { - return nil, err - } - l := &fileStore{ - persistentFile: path, - memoryStore: NewMemoryStore(), - } - - if err := l.load(); err != nil { - log.Fatalf("load failed, file: %s, err: %v", l.persistentFile, err) - } - - return l, nil -} - -// Add adds the given service to file Store -func (l *fileStore) Add(s ServiceUnderTest) error { - if err := l.memoryStore.Add(s); err != nil { - return err - } - - // persistent to local store - l.mu.Lock() - defer l.mu.Unlock() - return l.appendToFile(s) -} - -// Get returns the registered service information with the given name -func (l *fileStore) Get(name string) []string { - return l.memoryStore.Get(name) -} - -// Get returns all the registered service information -func (l *fileStore) GetAll() map[string][]string { - return l.memoryStore.GetAll() -} - -// Remove the service from the memory store and the file store -func (l *fileStore) Remove(addr string) error { - err := l.memoryStore.Remove(addr) - if err != nil { - return err - } - - return l.Set(l.memoryStore.GetAll()) -} - -// Init cleanup all the registered service information -// and the local persistent file -func (l *fileStore) Init() error { - if err := l.memoryStore.Init(); err != nil { - return err - } - - l.mu.Lock() - defer l.mu.Unlock() - if err := os.Remove(l.persistentFile); err != nil && !os.IsNotExist(err) { - return fmt.Errorf("failed to delete file %s, err: %v", l.persistentFile, err) - } - - return nil -} - -// load all registered service from file to memory -func (l *fileStore) load() error { - var svrsMap = make(map[string][]string, 0) - - f, err := os.Open(l.persistentFile) - if err != nil { - if os.IsNotExist(err) { - return nil - } - return fmt.Errorf("failed to open file, path: %s, err: %v", l.persistentFile, err) - } - defer f.Close() - - ns := bufio.NewScanner(f) - for ns.Scan() { - line := ns.Text() - ss := strings.FieldsFunc(line, split) - - // TODO: use regex - if len(ss) == 2 { - if urls, ok := svrsMap[ss[0]]; ok { - urls = append(urls, ss[1]) - svrsMap[ss[0]] = urls - } else { - svrsMap[ss[0]] = []string{ss[1]} - } - } - } - - if err := ns.Err(); err != nil { - return fmt.Errorf("read file failed, file: %s, err: %v", l.persistentFile, err) - } - - // set information to memory - l.memoryStore.Set(svrsMap) - return nil -} - -func (l *fileStore) Set(services map[string][]string) error { - l.mu.Lock() - defer l.mu.Unlock() - - // no error will return from memorystore.set - err := l.memoryStore.Set(services) - if err != nil { - return err - } - - f, err := os.OpenFile(l.persistentFile, os.O_TRUNC|os.O_WRONLY|os.O_CREATE, 0600) - if err != nil { - return err - } - - s := "" - for name, addrs := range services { - for _, addr := range addrs { - s += fmt.Sprintf("%s&%s\n", name, addr) - } - } - - _, err = f.WriteString(s) - if err != nil { - return err - } - - return f.Sync() -} - -func (l *fileStore) appendToFile(s ServiceUnderTest) error { - f, err := os.OpenFile(l.persistentFile, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0600) - if err != nil { - return err - } - defer f.Close() - - _, err = f.WriteString(format(s) + "\n") - if err != nil { - return err - } - - f.Sync() - return nil -} - -func format(s ServiceUnderTest) string { - return fmt.Sprintf("%s&%s", s.Name, s.Address) -} - -func split(r rune) bool { - return r == '&' -} - -// memoryStore holds the registered services only into memory -type memoryStore struct { - mu sync.RWMutex - servicesMap map[string][]string -} - -// NewMemoryStore creates a memory store -func NewMemoryStore() Store { - return &memoryStore{ - servicesMap: make(map[string][]string, 0), - } -} - -// Add adds the given service to MemoryStore -func (l *memoryStore) Add(s ServiceUnderTest) error { - l.mu.Lock() - defer l.mu.Unlock() - // load to memory - if addrs, ok := l.servicesMap[s.Name]; ok { - for _, addr := range addrs { - if addr == s.Address { - log.Printf("service registered already, name: %s, address: %s", s.Name, s.Address) - return ErrServiceAlreadyRegistered - } - } - addrs = append(addrs, s.Address) - l.servicesMap[s.Name] = addrs - } else { - l.servicesMap[s.Name] = []string{s.Address} - } - - return nil -} - -// Get returns the registered service information with the given name -func (l *memoryStore) Get(name string) []string { - l.mu.RLock() - defer l.mu.RUnlock() - return l.servicesMap[name] -} - -// Get returns all the registered service information -func (l *memoryStore) GetAll() map[string][]string { - res := make(map[string][]string) - l.mu.RLock() - defer l.mu.RUnlock() - for k, v := range l.servicesMap { - res[k] = append(make([]string, 0, len(v)), v...) - } - return res -} - -// Init cleanup all the registered service information -// and the local persistent file -func (l *memoryStore) Init() error { - l.mu.Lock() - defer l.mu.Unlock() - - l.servicesMap = make(map[string][]string, 0) - return nil -} - -func (l *memoryStore) Set(services map[string][]string) error { - l.mu.Lock() - defer l.mu.Unlock() - - l.servicesMap = services - - return nil -} - -// Remove one service from the memory store -// if service is not fount, return "no service found" error -func (l *memoryStore) Remove(removeAddr string) error { - l.mu.Lock() - defer l.mu.Unlock() - - flag := false - for name, addrs := range l.servicesMap { - newAddrs := make([]string, 0) - for _, addr := range addrs { - if removeAddr != addr { - newAddrs = append(newAddrs, addr) - } else { - flag = true - } - } - // if no services left, remove by name - if len(newAddrs) == 0 { - delete(l.servicesMap, name) - } else { - l.servicesMap[name] = newAddrs - } - } - - if !flag { - return fmt.Errorf("no service found") - } - - return nil -} diff --git a/pkg/cover/store_test.go b/pkg/cover/store_test.go deleted file mode 100644 index bf3201f..0000000 --- a/pkg/cover/store_test.go +++ /dev/null @@ -1,130 +0,0 @@ -/* - Copyright 2020 Qiniu Cloud (qiniu.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 cover - -import ( - "fmt" - "testing" - - "github.com/stretchr/testify/assert" -) - -func TestLocalStore(t *testing.T) { - localStore, err := NewFileStore("_svrs_address.txt") - assert.NoError(t, err) - var tc1 = ServiceUnderTest{ - Name: "a", - Address: "http://127.0.0.1", - } - var tc2 = ServiceUnderTest{ - Name: "b", - Address: "http://127.0.0.2", - } - var tc3 = ServiceUnderTest{ - Name: "c", - Address: "http://127.0.0.3", - } - var tc4 = ServiceUnderTest{ - Name: "a", - Address: "http://127.0.0.4", - } - assert.NoError(t, localStore.Add(tc1)) - assert.Equal(t, localStore.Add(tc1), ErrServiceAlreadyRegistered) - assert.NoError(t, localStore.Add(tc2)) - assert.NoError(t, localStore.Add(tc3)) - assert.NoError(t, localStore.Add(tc4)) - addrs := localStore.Get(tc1.Name) - if len(addrs) != 2 { - t.Error("unexpected result") - } - - for _, addr := range addrs { - if addr != tc1.Address && addr != tc4.Address { - t.Error("get address failed") - } - } - - if len(localStore.GetAll()) != 3 { - t.Error("local store check failed") - } - - localStoreNew, err := NewFileStore("_svrs_address.txt") - assert.NoError(t, err) - assert.Equal(t, localStore.GetAll(), localStoreNew.GetAll()) - - localStore.Init() - if len(localStore.GetAll()) != 0 { - t.Error("local store init failed") - } -} - -func TestMemoryStoreRemove(t *testing.T) { - store := NewMemoryStore() - s1 := ServiceUnderTest{Name: "test", Address: "http://127.0.0.1:8900"} - s2 := ServiceUnderTest{Name: "test2", Address: "http://127.0.0.1:8901"} - s3 := ServiceUnderTest{Name: "test2", Address: "http://127.0.0.1:8902"} - - _ = store.Add(s1) - _ = store.Add(s2) - _ = store.Add(s3) - - ss1 := store.Get("test") - assert.Equal(t, 1, len(ss1)) - err := store.Remove("http://127.0.0.1:8900") - assert.NoError(t, err) - ss1 = store.Get("test") - assert.Nil(t, ss1) - - ss2 := store.Get("test2") - assert.Equal(t, 2, len(ss2)) - err = store.Remove("http://127.0.0.1:8901") - assert.NoError(t, err) - ss2 = store.Get("test2") - assert.Equal(t, 1, len(ss2)) - - err = store.Remove("http") - assert.Error(t, err, fmt.Errorf("no service found")) -} - -func TestFileStoreRemove(t *testing.T) { - store, _ := NewFileStore("_svrs_address.txt") - _ = store.Init() - s1 := ServiceUnderTest{Name: "test", Address: "http://127.0.0.1:8900"} - s2 := ServiceUnderTest{Name: "test2", Address: "http://127.0.0.1:8901"} - s3 := ServiceUnderTest{Name: "test2", Address: "http://127.0.0.1:8902"} - - _ = store.Add(s1) - _ = store.Add(s2) - _ = store.Add(s3) - - ss1 := store.Get("test") - assert.Equal(t, 1, len(ss1)) - err := store.Remove("http://127.0.0.1:8900") - assert.NoError(t, err) - ss1 = store.Get("test") - assert.Nil(t, ss1) - - ss2 := store.Get("test2") - assert.Equal(t, 2, len(ss2)) - err = store.Remove("http://127.0.0.1:8901") - assert.NoError(t, err) - ss2 = store.Get("test2") - assert.Equal(t, 1, len(ss2)) - - err = store.Remove("http") - assert.Error(t, err, fmt.Errorf("no service found")) -} diff --git a/pkg/cover/template.go b/pkg/cover/template.go new file mode 100644 index 0000000..7e39a7c --- /dev/null +++ b/pkg/cover/template.go @@ -0,0 +1,26 @@ +package cover + +import ( + _ "embed" + "text/template" +) + +var coverBridgeTmpl = template.Must(template.New("coverBridge").Parse(coverBridge)) + +const coverBridge = ` +// Code generated by goc system. DO NOT EDIT. + +package main + +import _ "{{.CoverImportPath}}" +` + +var coverMainTmpl = template.Must(template.New("coverMain").Parse(coverMain)) + +//go:embed agent.tpl +var coverMain string + +var coverWatchTmpl = template.Must(template.New("coverWatch").Parse(coverWatch)) + +//go:embed agentwatch.tpl +var coverWatch string diff --git a/pkg/flag/build_flags.go b/pkg/flag/build_flags.go new file mode 100644 index 0000000..ee88900 --- /dev/null +++ b/pkg/flag/build_flags.go @@ -0,0 +1,120 @@ +package flag + +import ( + "flag" + "os" + "path/filepath" + + "github.com/qiniu/goc/v2/pkg/config" + "github.com/qiniu/goc/v2/pkg/log" + "github.com/spf13/cobra" + "github.com/spf13/pflag" +) + +var buildUsage string = `Usage: + goc build [-o output] [build flags] [packages] [goc flags] + +The [goc flags] can be placed in anywhere in the command line. +However, other flags' order are same with the go official command. +` + +// BuildCmdArgsParse parse both go flags and goc flags, it rewrite go flags if +// necessary, and returns all non-flag arguments. +// +// 吞下 [packages] 之前所有的 flags. +func BuildCmdArgsParse(cmd *cobra.Command, args []string) []string { + // 首先解析 cobra 定义的 flag + allFlagSets := cmd.Flags() + // 因为 args 里面含有 go 的 flag,所以需要忽略解析 go flag 的错误 + allFlagSets.Init("GOC", pflag.ContinueOnError) + allFlagSets.Parse(args) + + // 重写 help + helpFlag := allFlagSets.Lookup("help") + + if helpFlag.Changed { + printHelp(buildUsage, cmd) + } + // 删除 help flag + args = findAndDelHelpFlag(args) + + // 必须手动调用 + // 由于关闭了 cobra 的 flag parse,root PersistentPreRun 调用时,log.NewLogger 并没有拿到 debug 值 + log.NewLogger() + + // 删除 cobra 定义的 flag + allFlagSets.Visit(func(f *pflag.Flag) { + args = findAndDelGocFlag(args, f.Name, f.Value.String()) + }) + + // 然后解析 go 的 flag + goFlagSets := flag.NewFlagSet("GO", flag.ContinueOnError) + addBuildFlags(goFlagSets) + addOutputFlags(goFlagSets) + err := goFlagSets.Parse(args) + if err != nil { + log.Fatalf("%v", err) + } + + // 找出设置的 go flag + curWd, err := os.Getwd() + if err != nil { + log.Fatalf("fail to get current working directory: %v", err) + } + config.GocConfig.CurWd = curWd + flags := make([]string, 0) + goFlagSets.Visit(func(f *flag.Flag) { + // 将用户指定 -o 改成绝对目录 + if f.Name == "o" { + outputDir := f.Value.String() + outputDir, err := filepath.Abs(outputDir) + if err != nil { + log.Fatalf("output flag is not valid: %v", err) + } + flags = append(flags, "-o", outputDir) + } else { + flags = append(flags, "-"+f.Name, f.Value.String()) + } + }) + + config.GocConfig.Goflags = flags + + return goFlagSets.Args() +} + +func findAndDelGocFlag(a []string, x string, v string) []string { + new := make([]string, 0, len(a)) + x = "--" + x + x_v := x + "=" + v + for i := 0; i < len(a); i++ { + if a[i] == "--debug" { + // debug 是 bool,就一个元素 + continue + } else if a[i] == x { + // 有 goc flag 长这样 --mode watch + i++ + continue + } else if a[i] == x_v { + // 有 goc flag 长这样 --mode=watch + continue + } else { + // 剩下的是 go flag + new = append(new, a[i]) + } + } + + return new +} + +func findAndDelHelpFlag(a []string) []string { + new := make([]string, 0, len(a)) + for _, v := range a { + if v == "--help" || v == "-h" { + continue + } else { + new = append(new, v) + } + } + + return new +} diff --git a/pkg/flag/flags.go b/pkg/flag/flags.go new file mode 100644 index 0000000..6cbfb1a --- /dev/null +++ b/pkg/flag/flags.go @@ -0,0 +1,40 @@ +package flag + +import ( + "flag" + + "github.com/qiniu/goc/v2/pkg/config" +) + +func addBuildFlags(cmdSet *flag.FlagSet) { + cmdSet.BoolVar(&config.GoConfig.BuildA, "a", false, "") + cmdSet.BoolVar(&config.GoConfig.BuildN, "n", false, "") + cmdSet.IntVar(&config.GoConfig.BuildP, "p", 4, "") + cmdSet.BoolVar(&config.GoConfig.BuildV, "v", false, "") + cmdSet.BoolVar(&config.GoConfig.BuildX, "x", false, "") + cmdSet.StringVar(&config.GoConfig.BuildBuildmode, "buildmode", "default", "") + cmdSet.StringVar(&config.GoConfig.BuildMod, "mod", "", "") + cmdSet.StringVar(&config.GoConfig.Installsuffix, "installsuffix", "", "") + + // 类型和 go 原生的不一样,这里纯粹是为了 parse 并传递给 go + cmdSet.StringVar(&config.GoConfig.BuildAsmflags, "asmflags", "", "") + cmdSet.StringVar(&config.GoConfig.BuildCompiler, "compiler", "", "") + cmdSet.StringVar(&config.GoConfig.BuildGcflags, "gcflags", "", "") + cmdSet.StringVar(&config.GoConfig.BuildGccgoflags, "gccgoflags", "", "") + // mod related + cmdSet.BoolVar(&config.GoConfig.ModCacheRW, "modcacherw", false, "") + cmdSet.StringVar(&config.GoConfig.ModFile, "modfile", "", "") + cmdSet.StringVar(&config.GoConfig.BuildLdflags, "ldflags", "", "") + cmdSet.BoolVar(&config.GoConfig.BuildLinkshared, "linkshared", false, "") + cmdSet.StringVar(&config.GoConfig.BuildPkgdir, "pkgdir", "", "") + cmdSet.BoolVar(&config.GoConfig.BuildRace, "race", false, "") + cmdSet.BoolVar(&config.GoConfig.BuildMSan, "msan", false, "") + cmdSet.StringVar(&config.GoConfig.BuildTags, "tags", "", "") + cmdSet.StringVar(&config.GoConfig.BuildToolexec, "toolexec", "", "") + cmdSet.BoolVar(&config.GoConfig.BuildTrimpath, "trimpath", false, "") + cmdSet.BoolVar(&config.GoConfig.BuildWork, "work", false, "") +} + +func addOutputFlags(cmdSet *flag.FlagSet) { + cmdSet.StringVar(&config.GoConfig.BuildO, "o", "", "") +} diff --git a/pkg/flag/help.go b/pkg/flag/help.go new file mode 100644 index 0000000..78fe230 --- /dev/null +++ b/pkg/flag/help.go @@ -0,0 +1,20 @@ +package flag + +import ( + "fmt" + + "github.com/spf13/cobra" +) + +func printHelp(usage string, cmd *cobra.Command) { + fmt.Println(usage) + + flags := cmd.LocalFlags() + globalFlags := cmd.Parent().PersistentFlags() + + fmt.Println("Flags:") + fmt.Println(flags.FlagUsages()) + + fmt.Println("Global Flags:") + fmt.Println(globalFlags.FlagUsages()) +} diff --git a/pkg/flag/packages.go b/pkg/flag/packages.go new file mode 100644 index 0000000..6c7ca27 --- /dev/null +++ b/pkg/flag/packages.go @@ -0,0 +1,193 @@ +package flag + +import ( + "fmt" + "os" + "path/filepath" + "strings" + + "github.com/qiniu/goc/v2/pkg/config" + "github.com/qiniu/goc/v2/pkg/log" +) + +// GetPackagesDir parse [pacakges] part of args, it will fatal if error encountered +// +// 函数获取 1: [packages] 所在的目录位置,供后续插桩使用。 +// +// 函数获取 2: 如果参数是 *.go,第一个 .go 文件的文件名。go build 中,二进制名字既可能是目录名也可能是文件名,和参数类型有关。 +// +// 如果 [packages] 非法(即不符合 go 原生的定义),则返回对应错误 +// 这里只考虑 go mod 的方式 +func GetPackagesDir(patterns []string) { + packages := make([]string, 0) + for _, p := range patterns { + // patterns 只支持两种格式 + // 1. 要么是直接指向某些 .go 文件的相对/绝对路径 + if strings.HasSuffix(p, ".go") { + if fi, err := os.Stat(p); err == nil && !fi.IsDir() { + // check if valid + if err := goFilesPackage(patterns); err != nil { + log.Fatalf("%v", err) + } + + // 获取相对于 current working directory 对路径 + for _, p := range patterns { + if filepath.IsAbs(p) { + relPath, err := filepath.Rel(config.GocConfig.CurWd, p) + if err != nil { + log.Fatalf("fail to get [packages] relative path from current working directory: %v", err) + } + packages = append(packages, relPath) + } else { + packages = append(packages, p) + } + } + // fix: go build ./xx/main.go 需要转换为 + // go build ./xx/main.go ./xx/goc-cover-agent-apis-auto-generated-11111-22222-bridge.go + dir := filepath.Dir(packages[0]) + packages = append(packages, filepath.Join(dir, "goc-cover-agent-apis-auto-generated-11111-22222-bridge.go")) + config.GocConfig.Packages = packages + + return + } + } + } + + // 2. 要么是 import path + config.GocConfig.Packages = patterns +} + +// goFilesPackage 对一组 go 文件解析,判断是否合法 +// go 本身还判断语法上是否是同一个 package,goc 这里不做解析 +// 1. 都是 *.go 文件? +// 2. *.go 文件都在同一个目录? +// 3. *.go 文件存在? +func goFilesPackage(gofiles []string) error { + // 1. 必须都是 *.go 结尾 + for _, f := range gofiles { + if !strings.HasSuffix(f, ".go") { + return fmt.Errorf("named files must be .go files: %s", f) + } + } + + var dir string + for _, file := range gofiles { + // 3. 文件都存在? + fi, err := os.Stat(file) + if err != nil { + return err + } + + // 2.1 有可能以 *.go 结尾的目录 + if fi.IsDir() { + return fmt.Errorf("%s is a directory, should be a Go file", file) + } + + // 2.2 所有 *.go 必须在同一个目录内 + dir1, _ := filepath.Split(file) + if dir1 == "" { + dir1 = "./" + } + + if dir == "" { + dir = dir1 + } else if dir != dir1 { + return fmt.Errorf("named files must all be in one directory: have %s and %s", dir, dir1) + } + } + + return nil +} + +// getDirFromImportPaths return the import path's real abs directory +// +// 该函数接收到的只有 dir 或 import path,file 在上一步已被排除 +// 只考虑 go modules 的情况 +func getDirFromImportPaths(patterns []string) (string, error) { + // no import path, pattern = current wd + if len(patterns) == 0 { + wd, err := os.Getwd() + if err != nil { + return "", fmt.Errorf("fail to parse import path: %w", err) + } + return wd, nil + } + + // 为了简化插桩的逻辑,goc 对 import path 要求必须都在同一个目录 + // 所以干脆只允许一个 pattern 得了 -_- + // 对于 goc build/run 来说本身就是只能在一个目录内 + // 对于 goc install 来讲,这个行为就和 go install 不同,不过多 import path 较少见 >_<,先忽略 + if len(patterns) > 1 { + return "", fmt.Errorf("goc only support one import path now") + } + + pattern := patterns[0] + switch { + // case isLocalImport(pattern) || filepath.IsAbs(pattern): + // dir1, err := filepath.Abs(pattern) + // if err != nil { + // return "", fmt.Errorf("error (%w) get directory from the import path: %v", err, pattern) + // } + // if _, err := os.Stat(dir1); err != nil { + // return "", fmt.Errorf("error (%w) get directory from the import path: %v", err, pattern) + // } + // return dir1, nil + + case strings.Contains(pattern, "..."): + i := strings.Index(pattern, "...") + dir, _ := filepath.Split(pattern[:i]) + dir, _ = filepath.Abs(dir) + if _, err := os.Stat(dir); err != nil { + return "", fmt.Errorf("error (%w) get directory from the import path: %v", err, pattern) + } + return dir, nil + + case strings.IndexByte(pattern, '@') > 0: + return "", fmt.Errorf("import path with @ version query is not supported in goc") + + case isMetaPackage(pattern): + return "", fmt.Errorf("`std`, `cmd`, `all` import path is not supported by goc") + + default: // 到这一步认为 pattern 是相对路径或者绝对路径 + dir1, err := filepath.Abs(pattern) + if err != nil { + return "", fmt.Errorf("error (%w) get directory from the import path: %v", err, pattern) + } + if _, err := os.Stat(dir1); err != nil { + return "", fmt.Errorf("error (%w) get directory from the import path: %v", err, pattern) + } + + return dir1, nil + } +} + +// isLocalImport reports whether the import path is +// a local import path, like ".", "..", "./foo", or "../foo" +func isLocalImport(path string) bool { + return path == "." || path == ".." || + strings.HasPrefix(path, "./") || strings.HasPrefix(path, "../") +} + +// isMetaPackage checks if the name is a reserved package name +func isMetaPackage(name string) bool { + return name == "std" || name == "cmd" || name == "all" +} + +// find direct path of current project which contains go.mod +func findModuleRoot(dir string) string { + dir = filepath.Clean(dir) + + // look for enclosing go.mod + for { + if fi, err := os.Stat(filepath.Join(dir, "go.mod")); err == nil && !fi.IsDir() { + return dir + } + d := filepath.Dir(dir) + if d == dir { + break + } + dir = d + } + + return "" +} diff --git a/pkg/github/github.go b/pkg/github/github.go deleted file mode 100644 index 8b9092f..0000000 --- a/pkg/github/github.go +++ /dev/null @@ -1,203 +0,0 @@ -/* - Copyright 2020 Qiniu Cloud (qiniu.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 github - -import ( - "bytes" - "context" - "fmt" - "io/ioutil" - "os" - "strconv" - "strings" - - "github.com/google/go-github/github" - "github.com/hashicorp/go-retryablehttp" - "github.com/olekukonko/tablewriter" - "github.com/sirupsen/logrus" - "golang.org/x/oauth2" - - "github.com/qiniu/goc/pkg/cover" -) - -// CommentsPrefix is the prefix when commenting on Github Pull Requests -// It is also the flag when checking whether the target comment exists or not to avoid duplicate -const CommentsPrefix = "The following is the coverage report on the affected files." - -// PrComment is the interface of the entry which is able to comment on Github Pull Requests -type PrComment interface { - CreateGithubComment(commentPrefix string, diffCovList cover.DeltaCovList) (err error) - PostComment(content, commentPrefix string) error - EraseHistoryComment(commentPrefix string) error - GetPrChangedFiles() (files []string, err error) - GetCommentFlag() string -} - -// GitPrComment is the entry which is able to comment on Github Pull Requests -type GitPrComment struct { - RobotUserName string - RepoOwner string - RepoName string - CommentFlag string - PrNumber int - Ctx context.Context - opt *github.ListOptions - GithubClient *github.Client -} - -// NewPrClient creates an Client which be able to comment on Github Pull Request -func NewPrClient(githubTokenPath, repoOwner, repoName, prNumStr, botUserName, commentFlag string) *GitPrComment { - var client *github.Client - - // performs automatic retries when connection error occurs or a 500-range response code received (except 501) - retryClient := retryablehttp.NewClient() - ctx := context.WithValue(context.Background(), oauth2.HTTPClient, retryClient.StandardClient()) - - prNum, err := strconv.Atoi(prNumStr) - if err != nil { - logrus.WithError(err).Fatalf("Failed to convert prNumStr(=%v) to int.\n", prNumStr) - } - token, err := ioutil.ReadFile(githubTokenPath) - if err != nil { - logrus.WithError(err).Fatalf("Failed to get github token.\n") - } - ts := oauth2.StaticTokenSource( - &oauth2.Token{AccessToken: strings.TrimSpace(string(token))}, - ) - tc := oauth2.NewClient(ctx, ts) - client = github.NewClient(tc) - - return &GitPrComment{ - RobotUserName: botUserName, - RepoOwner: repoOwner, - RepoName: repoName, - PrNumber: prNum, - CommentFlag: commentFlag, - Ctx: ctx, - opt: &github.ListOptions{Page: 1}, - GithubClient: client, - } -} - -// CreateGithubComment post github comment of diff coverage -func (c *GitPrComment) CreateGithubComment(commentPrefix string, diffCovList cover.DeltaCovList) (err error) { - if len(diffCovList) == 0 { - logrus.Printf("Detect 0 files coverage diff, will not comment to github.") - return nil - } - content := GenCommentContent(commentPrefix, diffCovList) - - err = c.PostComment(content, commentPrefix) - if err != nil { - logrus.WithError(err).Fatalf("Post comment to github failed.") - } - - return -} - -// PostComment post comment on github. It erased the old one if existed to avoid duplicate -func (c *GitPrComment) PostComment(content, commentPrefix string) error { - //step1: erase history similar comment to avoid too many comment for same job - err := c.EraseHistoryComment(commentPrefix) - if err != nil { - return err - } - - //step2: post comment with new result - comment := &github.IssueComment{ - Body: &content, - } - _, _, err = c.GithubClient.Issues.CreateComment(c.Ctx, c.RepoOwner, c.RepoName, c.PrNumber, comment) - if err != nil { - return err - } - - return nil -} - -// EraseHistoryComment erase history similar comment before post again -func (c *GitPrComment) EraseHistoryComment(commentPrefix string) error { - comments, _, err := c.GithubClient.Issues.ListComments(c.Ctx, c.RepoOwner, c.RepoName, c.PrNumber, nil) - if err != nil { - logrus.Errorf("list PR comments failed.") - return err - } - logrus.Infof("the count of history comments by %s is: %v", c.RobotUserName, len(comments)) - - for _, cm := range comments { - if *cm.GetUser().Login == c.RobotUserName && strings.HasPrefix(cm.GetBody(), commentPrefix) { - _, err = c.GithubClient.Issues.DeleteComment(c.Ctx, c.RepoOwner, c.RepoName, *cm.ID) - if err != nil { - logrus.Errorf("delete PR comments %d failed.", *cm.ID) - return err - } - } - } - - return nil -} - -// GetPrChangedFiles get github pull request changes file list -func (c *GitPrComment) GetPrChangedFiles() (files []string, err error) { - var commitFiles []*github.CommitFile - for { - f, resp, err := c.GithubClient.PullRequests.ListFiles(c.Ctx, c.RepoOwner, c.RepoName, c.PrNumber, c.opt) - if err != nil { - logrus.Errorf("Get PR changed file failed. repoOwner is: %s, repoName is: %s, prNum is: %d", c.RepoOwner, c.RepoName, c.PrNumber) - return nil, err - } - commitFiles = append(commitFiles, f...) - if resp.NextPage == 0 { - break - } - c.opt.Page = resp.NextPage - } - logrus.Infof("get %d PR changed files:", len(commitFiles)) - for _, file := range commitFiles { - files = append(files, *file.Filename) - logrus.Infof("%s", *file.Filename) - } - return -} - -// GetCommentFlag get CommentFlag from the GitPrComment -func (c *GitPrComment) GetCommentFlag() string { - return c.CommentFlag -} - -// GenCommentContent generate github comment content based on diff coverage and commentFlag -func GenCommentContent(commentPrefix string, delta cover.DeltaCovList) string { - var buf bytes.Buffer - table := tablewriter.NewWriter(&buf) - table.SetHeader([]string{"File", "Base Coverage", "New Coverage", "Delta"}) - table.SetAutoFormatHeaders(false) - table.SetBorders(tablewriter.Border{Left: true, Top: false, Right: true, Bottom: false}) - table.SetCenterSeparator("|") - table.SetColumnAlignment([]int{tablewriter.ALIGN_LEFT, tablewriter.ALIGN_CENTER, tablewriter.ALIGN_CENTER, tablewriter.ALIGN_CENTER}) - for _, d := range delta { - table.Append([]string{fmt.Sprintf("[%s](%s)", d.FileName, d.LineCovLink), d.BasePer, d.NewPer, d.DeltaPer}) - } - table.Render() - - content := []string{ - commentPrefix, - fmt.Sprintf("Say `/test %s` to re-run this coverage report", os.Getenv("JOB_NAME")), - buf.String(), - } - - return strings.Join(content, "\n") -} diff --git a/pkg/github/github_test.go b/pkg/github/github_test.go deleted file mode 100644 index ffe7d1f..0000000 --- a/pkg/github/github_test.go +++ /dev/null @@ -1,176 +0,0 @@ -/* - Copyright 2020 Qiniu Cloud (qiniu.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 github - -import ( - "encoding/json" - "fmt" - "net/http" - "net/http/httptest" - "net/url" - "os" - "testing" - - "github.com/google/go-github/github" - "github.com/julienschmidt/httprouter" - "github.com/stretchr/testify/assert" - "golang.org/x/net/context" - - "github.com/qiniu/goc/pkg/cover" -) - -const ( - // baseURLPath is a non-empty Client.BaseURL path to use during tests, - // to ensure relative URLs are used for all endpoints. See issue #752. - baseURLPath = "/api-v3" -) - -// setup sets up a test HTTP server along with a github.Client that is -// configured to talk to that test server. Tests should register handlers on -// mux which provide mock responses for the API method being tested. -func setup() (client *github.Client, router *httprouter.Router, serverURL string, teardown func()) { - // router is the HTTP request multiplexer used with the test server. - router = httprouter.New() - - // We want to ensure that tests catch mistakes where the endpoint URL is - // specified as absolute rather than relative. It only makes a difference - // when there's a non-empty base URL path. So, use that. See issue #752. - apiHandler := http.NewServeMux() - apiHandler.Handle(baseURLPath+"/", http.StripPrefix(baseURLPath, router)) - apiHandler.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) { - fmt.Fprintln(os.Stderr, "FAIL: Client.BaseURL path prefix is not preserved in the request URL:") - fmt.Fprintln(os.Stderr) - fmt.Fprintln(os.Stderr, "\t"+req.URL.String()) - fmt.Fprintln(os.Stderr) - fmt.Fprintln(os.Stderr, "\tDid you accidentally use an absolute endpoint URL rather than relative?") - fmt.Fprintln(os.Stderr, "\tSee https://github.com/google/go-github/issues/752 for information.") - http.Error(w, "Client.BaseURL path prefix is not preserved in the request URL.", http.StatusInternalServerError) - }) - - // server is a test HTTP server used to provide mock API responses. - server := httptest.NewServer(apiHandler) - - // client is the GitHub client being tested and is - // configured to use test server. - client = github.NewClient(nil) - url, _ := url.Parse(server.URL + baseURLPath + "/") - client.BaseURL = url - client.UploadURL = url - - return client, router, server.URL, server.Close -} - -func TestNewPrClient(t *testing.T) { - items := []struct { - token string - repoOwner string - repoName string - prNumStr string - botUserName string - commentFlag string - expectPrNum int - }{ - {token: "github_test.go", repoOwner: "qiniu", repoName: "goc", prNumStr: "1", botUserName: "qiniu-bot", commentFlag: "test", expectPrNum: 1}, - } - - for _, tc := range items { - prClient := NewPrClient(tc.token, tc.repoOwner, tc.repoName, tc.prNumStr, tc.botUserName, tc.commentFlag) - assert.Equal(t, tc.expectPrNum, prClient.PrNumber) - } -} - -func TestCreateGithubComment(t *testing.T) { - client, router, _, teardown := setup() - defer teardown() - - var coverList = cover.DeltaCovList{{FileName: "fake-coverage", BasePer: "50.0%", NewPer: "75.0%", DeltaPer: "25.0%"}} - expectContent := GenCommentContent("", coverList) - comment := &github.IssueComment{ - Body: &expectContent, - } - - // create comment: https://developer.github.com/v3/issues/comments/#create-a-comment - router.HandlerFunc("POST", "/repos/qiniu/goc/issues/1/comments", func(w http.ResponseWriter, r *http.Request) { - v := new(github.IssueComment) - json.NewDecoder(r.Body).Decode(v) - assert.Equal(t, v, comment) - - fmt.Fprint(w, `{"id":1}`) - }) - - // list comment: https://developer.github.com/v3/issues/comments/#list-comments-on-an-issue - router.HandlerFunc("GET", "/repos/qiniu/goc/issues/1/comments", func(w http.ResponseWriter, r *http.Request) { - fmt.Fprint(w, `[{"id":1,"user": {"login": "qiniu-bot"}}]`) - }) - - // delete comment: https://developer.github.com/v3/issues/comments/#edit-a-comment - router.HandlerFunc("DELETE", "/repos/qiniu/goc/issues/comments/1", func(w http.ResponseWriter, r *http.Request) { - }) - - p := GitPrComment{ - RobotUserName: "qiniu-bot", - RepoOwner: "qiniu", - RepoName: "goc", - CommentFlag: "", - PrNumber: 1, - Ctx: context.Background(), - opt: nil, - GithubClient: client, - } - - p.CreateGithubComment("", coverList) -} - -func TestCreateGithubCommentError(t *testing.T) { - p := &GitPrComment{} - err := p.CreateGithubComment("", cover.DeltaCovList{}) - assert.NoError(t, err) -} - -func TestGetPrChangedFiles(t *testing.T) { - client, router, _, teardown := setup() - defer teardown() - - var expectFiles = []string{"src/qiniu.com/kodo/s3apiv2/bucket/bucket.go"} - - // list files API: https://developer.github.com/v3/pulls/#list-pull-requests-files - router.HandlerFunc("GET", "/repos/qiniu/goc/pulls/1/files", func(w http.ResponseWriter, r *http.Request) { - fmt.Fprint(w, `[{"filename":"src/qiniu.com/kodo/s3apiv2/bucket/bucket.go"}]`) - }) - - p := GitPrComment{ - RobotUserName: "qiniu-bot", - RepoOwner: "qiniu", - RepoName: "goc", - CommentFlag: "", - PrNumber: 1, - Ctx: context.Background(), - opt: nil, - GithubClient: client, - } - changedFiles, err := p.GetPrChangedFiles() - assert.Equal(t, err, nil) - assert.Equal(t, changedFiles, expectFiles) -} - -func TestGetCommentFlag(t *testing.T) { - p := GitPrComment{ - CommentFlag: "flag", - } - flag := p.GetCommentFlag() - assert.Equal(t, flag, p.CommentFlag) -} diff --git a/pkg/log/ci_logger.go b/pkg/log/ci_logger.go new file mode 100644 index 0000000..e8486d0 --- /dev/null +++ b/pkg/log/ci_logger.go @@ -0,0 +1,53 @@ +package log + +import "go.uber.org/zap" + +type ciLogger struct { + logger *zap.Logger +} + +func newCiLogger() *ciLogger { + logger, _ := zap.NewDevelopment() + // fix: increases the number of caller from always reporting the wrapper code as caller + logger = logger.WithOptions(zap.AddCallerSkip(2)) + zap.ReplaceGlobals(logger) + return &ciLogger{ + logger: logger, + } +} + +func (c *ciLogger) StartWait(message string) { + +} + +func (c *ciLogger) StopWait() { + +} + +func (c *ciLogger) Sync() { + c.logger.Sync() +} + +func (c *ciLogger) Debugf(format string, args ...interface{}) { + zap.S().Debugf(format, args...) +} + +func (c *ciLogger) Donef(format string, args ...interface{}) { + zap.S().Infof(format, args...) +} + +func (c *ciLogger) Infof(format string, args ...interface{}) { + zap.S().Infof(format, args...) +} + +func (c *ciLogger) Errorf(format string, args ...interface{}) { + zap.S().Errorf(format, args...) +} + +func (c *ciLogger) Warnf(format string, args ...interface{}) { + zap.S().Warnf(format, args...) +} + +func (c *ciLogger) Fatalf(format string, args ...interface{}) { + zap.S().Fatalf(format, args...) +} diff --git a/pkg/log/display.go b/pkg/log/display.go new file mode 100644 index 0000000..39b7813 --- /dev/null +++ b/pkg/log/display.go @@ -0,0 +1,16 @@ +package log + +import "github.com/mgutz/ansi" + +const banner = ` + __ _ ___ ___ + / _ |/ _ \ / __| +| (_| | (_) | (__ + \__, |\___/ \___| + |___/ + +` + +func DisplayGoc() { + stdout.Write([]byte(ansi.Color(banner, "cyan+b"))) +} diff --git a/pkg/log/loading_text.go b/pkg/log/loading_text.go new file mode 100644 index 0000000..e01d1f7 --- /dev/null +++ b/pkg/log/loading_text.go @@ -0,0 +1,115 @@ +package log + +import ( + "fmt" + "io" + "time" + + "github.com/mgutz/ansi" +) + +var tty = setupTTY() + +type loadingText struct { + message string + stream io.Writer + stopChan chan bool + startTimestamp int64 + cnt int +} + +func (l *loadingText) start() { + l.startTimestamp = time.Now().UnixNano() + + if l.stopChan == nil { + l.stopChan = make(chan bool) + } + + go func() { + l.render() + for { + select { + case <-l.stopChan: + return + case <-time.After(time.Millisecond * 100): + l.render() + } + } + }() +} + +func (l *loadingText) stop() { + l.stopChan <- true + l.stream.Write([]byte("\r")) + + for i := 0; i < len(l.message)+20; i++ { + l.stream.Write([]byte(" ")) + } + + l.stream.Write([]byte("\r")) +} + +func (l *loadingText) render() { + l.stream.Write([]byte("\r")) + + messagePrefix := []byte("[wait] ") + prefixLength := len(messagePrefix) + l.stream.Write([]byte(ansi.Color(string(messagePrefix), "cyan+b"))) + + timeElapsed := fmt.Sprintf("%v", (time.Now().UnixNano()-l.startTimestamp)/int64(time.Second)) + + message := []byte(l.getLoadingChar() + " " + l.message) + + messageSuffix := " (" + timeElapsed + "s) " + suffixLength := len(messageSuffix) + + terminalSize := tty.GetSize() + + // if the whole message is too long, then replace last words with ... + if terminalSize != nil && terminalSize.Width < uint16(prefixLength+len(message)+suffixLength) { + dots := []byte("...") + maxMessageLength := int(terminalSize.Width) - (prefixLength + suffixLength + len(dots) + 5) + + if maxMessageLength > 0 { + message = append(message[:maxMessageLength], dots...) + } + } + + message = append(message, messageSuffix...) + l.stream.Write(message) +} + +func (l *loadingText) getLoadingChar() string { + var loadingChar string + + switch l.cnt { + case 0: + loadingChar = "⠋" + case 1: + loadingChar = "⠙" + case 2: + loadingChar = "⠹" + case 3: + loadingChar = "⠸" + case 4: + loadingChar = "⠼" + case 5: + loadingChar = "⠴" + case 6: + loadingChar = "⠦" + case 7: + loadingChar = "⠧" + case 8: + loadingChar = "⠇" + case 9: + loadingChar = "⠏" + } + + l.cnt += 1 + + if l.cnt > 9 { + l.cnt = 0 + } + + return loadingChar +} diff --git a/pkg/log/log.go b/pkg/log/log.go new file mode 100644 index 0000000..7611c55 --- /dev/null +++ b/pkg/log/log.go @@ -0,0 +1,54 @@ +package log + +import ( + "github.com/qiniu/goc/v2/pkg/config" + "go.uber.org/zap/zapcore" +) + +var g Logger + +func NewLogger() { + if config.GocConfig.Debug == true { + g = newCiLogger() + } else { + g = &terminalLogger{ + level: zapcore.InfoLevel, + } + } +} + +func Debugf(format string, args ...interface{}) { + g.Debugf(format, args...) +} + +func Donef(format string, args ...interface{}) { + g.Donef(format, args...) +} + +func Infof(format string, args ...interface{}) { + g.Infof(format, args...) +} + +func Warnf(format string, args ...interface{}) { + g.Warnf(format, args...) +} + +func Fatalf(format string, args ...interface{}) { + g.Fatalf(format, args...) +} + +func Errorf(format string, args ...interface{}) { + g.Errorf(format, args...) +} + +func StartWait(message string) { + g.StartWait(message) +} + +func StopWait() { + g.StopWait() +} + +func Sync() { + g.Sync() +} diff --git a/pkg/log/logger.go b/pkg/log/logger.go new file mode 100644 index 0000000..97f0b2d --- /dev/null +++ b/pkg/log/logger.go @@ -0,0 +1,22 @@ +package log + +// Logger defines common interface for logging +type Logger interface { + Debugf(format string, args ...interface{}) + + Infof(format string, args ...interface{}) + + Warnf(format string, args ...interface{}) + + Fatalf(format string, args ...interface{}) + + Errorf(format string, args ...interface{}) + + Donef(format string, args ...interface{}) + + StartWait(message string) + StopWait() + + // Sync flushes cached log to disk, some log library needs this step + Sync() +} diff --git a/pkg/log/terminal.go b/pkg/log/terminal.go new file mode 100644 index 0000000..82aa81b --- /dev/null +++ b/pkg/log/terminal.go @@ -0,0 +1,22 @@ +package log + +import ( + "os" + + "k8s.io/kubectl/pkg/util/term" +) + +func setupTTY() term.TTY { + t := term.TTY{ + In: os.Stdin, + Out: os.Stdout, + } + + if !t.IsTerminalIn() { + return t + } + + t.Raw = true + + return t +} diff --git a/pkg/log/terminal_logger.go b/pkg/log/terminal_logger.go new file mode 100644 index 0000000..d4ca9a9 --- /dev/null +++ b/pkg/log/terminal_logger.go @@ -0,0 +1,176 @@ +package log + +import ( + "fmt" + "io" + "os" + "sync" + + goansi "github.com/k0kubun/go-ansi" + "github.com/mgutz/ansi" + "go.uber.org/zap/zapcore" +) + +// goansi works nicer on Windows platform +var stdout = goansi.NewAnsiStdout() +var stderr = goansi.NewAnsiStderr() + +type terminalLogger struct { + mutex sync.Mutex + level zapcore.Level + loadingText *loadingText +} + +type levelFuncType int32 + +const ( + fatalFn levelFuncType = iota + infoFn + errorFn + warnFn + debugFn + doneFn +) + +type levelFuncInfo struct { + tag string + color string + level zapcore.Level + stream io.Writer +} + +var levelFuncMap = map[levelFuncType]*levelFuncInfo{ + doneFn: { + tag: "[done] √ ", + color: "green+b", + level: zapcore.InfoLevel, + stream: stdout, + }, + debugFn: { + tag: "[debug] ", + color: "green+b", + level: zapcore.DebugLevel, + stream: stdout, + }, + infoFn: { + tag: "[info] ", + color: "cyan+b", + level: zapcore.InfoLevel, + stream: stdout, + }, + warnFn: { + tag: "[warn] ", + color: "magenta+b", + level: zapcore.WarnLevel, + stream: stdout, + }, + errorFn: { + tag: "[error] ", + color: "yellow+b", + level: zapcore.ErrorLevel, + stream: stdout, + }, + fatalFn: { + tag: "[fatal] ", + color: "red+b", + level: zapcore.FatalLevel, + stream: stdout, + }, +} + +func (t *terminalLogger) writeMessage(funcType levelFuncType, message string) { + funcInfo := levelFuncMap[funcType] + if t.level <= funcInfo.level { + // 如果当前有消息在加载,需先暂停 + if t.loadingText != nil { + t.loadingText.stop() + } + + funcInfo.stream.Write([]byte(ansi.Color(funcInfo.tag, funcInfo.color))) + funcInfo.stream.Write([]byte(message)) + + // 恢复加载 + if t.loadingText != nil && funcType != fatalFn { + t.loadingText.start() + } + } +} + +// StartWait prints a waiting message until StopWait is called +func (t *terminalLogger) StartWait(message string) { + t.mutex.Lock() + defer t.mutex.Unlock() + + // 撤销之前的加载 + if t.loadingText != nil { + t.loadingText.stop() + t.loadingText = nil + } + + // 创建新的加载字符串 + t.loadingText = &loadingText{ + message: message, + stream: goansi.NewAnsiStdout(), + } + + t.loadingText.start() +} + +// StopWait stops waiting +func (t *terminalLogger) StopWait() { + t.mutex.Lock() + defer t.mutex.Unlock() + + if t.loadingText != nil { + t.loadingText.stop() + t.loadingText = nil + } +} + +func (t *terminalLogger) Sync() { + +} + +func (t *terminalLogger) Debugf(format string, args ...interface{}) { + t.mutex.Lock() + defer t.mutex.Unlock() + + t.writeMessage(debugFn, fmt.Sprintf(format, args...)+"\n") +} + +func (t *terminalLogger) Donef(format string, args ...interface{}) { + t.mutex.Lock() + defer t.mutex.Unlock() + + t.writeMessage(doneFn, fmt.Sprintf(format, args...)+"\n") +} + +func (t *terminalLogger) Infof(format string, args ...interface{}) { + t.mutex.Lock() + defer t.mutex.Unlock() + + t.writeMessage(infoFn, fmt.Sprintf(format, args...)+"\n") +} + +func (t *terminalLogger) Errorf(format string, args ...interface{}) { + t.mutex.Lock() + defer t.mutex.Unlock() + + t.writeMessage(errorFn, fmt.Sprintf(format, args...)+"\n") +} + +func (t *terminalLogger) Warnf(format string, args ...interface{}) { + t.mutex.Lock() + defer t.mutex.Unlock() + + t.writeMessage(warnFn, fmt.Sprintf(format, args...)+"\n") +} + +func (t *terminalLogger) Fatalf(format string, args ...interface{}) { + t.mutex.Lock() + defer t.mutex.Unlock() + + t.writeMessage(fatalFn, fmt.Sprintf(format, args...)+"\n") + + os.Exit(1) +} diff --git a/pkg/prow/job.go b/pkg/prow/job.go deleted file mode 100644 index cebcdad..0000000 --- a/pkg/prow/job.go +++ /dev/null @@ -1,240 +0,0 @@ -/* - Copyright 2020 Qiniu Cloud (qiniu.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 prow - -import ( - "bufio" - "bytes" - "fmt" - "io/ioutil" - "os" - "os/exec" - "path" - "strconv" - "strings" - "time" - - "github.com/sirupsen/logrus" - - "github.com/qiniu/goc/pkg/cover" - "github.com/qiniu/goc/pkg/github" - "github.com/qiniu/goc/pkg/qiniu" -) - -// IProwAction defines the normal action in prow system -type IProwAction interface { - Fetch(BuildID, name string) []byte - RunPresubmit() error - RunPostsubmit() error - RunPeriodic() error -} - -// Job is a prowjob in prow -type Job struct { - JobName string - Org string - RepoName string - PRNumStr string - BuildId string //prow job build number - PostSubmitJob string - PostSubmitCoverProfile string - CovThreshold int - LocalProfilePath string - QiniuClient qiniu.Client - LocalArtifacts qiniu.Artifacts - GithubComment github.PrComment - FullDiff bool -} - -// Fetch the file from cloud -func (j *Job) Fetch(BuildID, name string) []byte { - return []byte{} -} - -// RunPresubmit run a presubmit job -func (j *Job) RunPresubmit() error { - // step1: get local profile cov - localP, err := cover.ReadFileToCoverList(j.LocalProfilePath) - if err != nil { - return fmt.Errorf("failed to get remote cover profile: %s", err.Error()) - } - - //step2: find the remote healthy cover profile from qiniu bucket - remoteProfile, err := qiniu.FindBaseProfileFromQiniu(j.QiniuClient, j.PostSubmitJob, j.PostSubmitCoverProfile) - if err != nil { - return fmt.Errorf("failed to get remote cover profile: %s", err.Error()) - } - if remoteProfile == nil { - logrus.Infof("get non healthy remoteProfile, do nothing") - return nil - } - baseP, err := cover.CovList(bytes.NewReader(remoteProfile)) - if err != nil { - return fmt.Errorf("failed to get remote cover profile: %s", err.Error()) - } - - // step3: get github pull request changed files' name and calculate diff cov between local and remote profile - changedFiles, deltaCovList, err := getFilesAndCovList(j.FullDiff, j.GithubComment, localP, baseP) - if err != nil { - return fmt.Errorf("Get files and covlist failed: %s", err.Error()) - } - - // step4: generate changed file html coverage - err = j.WriteChangedCov(changedFiles) - if err != nil { - return fmt.Errorf("filter local profile to %s with changed files failed: %s", j.LocalArtifacts.GetChangedProfileName(), err.Error()) - } - err = j.CreateChangedCovHtml() - if err != nil { - return fmt.Errorf("create changed file related coverage html failed: %s", err.Error()) - } - j.SetDeltaCovLinks(deltaCovList) - - // step5: post comment to github - commentPrefix := github.CommentsPrefix - if j.GithubComment.GetCommentFlag() != "" { - commentPrefix = fmt.Sprintf("**%s** ", j.GithubComment.GetCommentFlag()) + commentPrefix - } - if len(deltaCovList) > 0 { - totalDelta := cover.PercentStr(cover.TotalDelta(localP, baseP)) - deltaCovList = append(deltaCovList, cover.DeltaCov{FileName: "Total", BasePer: baseP.TotalPercentage(), NewPer: localP.TotalPercentage(), DeltaPer: totalDelta}) - } - err = j.GithubComment.CreateGithubComment(commentPrefix, deltaCovList) - if err != nil { - return fmt.Errorf("Post comment to github failed: %s", err.Error()) - } - - return nil -} - -// RunPostsubmit run a postsubmit job -func (j *Job) RunPostsubmit() error { - return nil -} - -// RunPeriodic run a periodic job -func (j *Job) RunPeriodic() error { - return nil -} - -//trim github filename to profile format: -// src/qiniu.com/kodo/io/io/io_svr.go -> qiniu.com/kodo/io/io/io_svr.go -func trimGhFileToProfile(ghFiles []string) (pFiles []string) { - //TODO: need compatible other situation - logrus.Infof("trim PR changed file name to:") - for _, f := range ghFiles { - file := strings.TrimPrefix(f, "src/") - logrus.Infof("%s", file) - pFiles = append(pFiles, file) - } - return -} - -// WriteChangedCov filter local profile with changed files and save to j.LocalArtifacts.ChangedProfileName -func (j *Job) WriteChangedCov(changedFiles []string) error { - p, err := ioutil.ReadFile(j.LocalProfilePath) - if err != nil { - logrus.Printf("Open file %s failed", j.LocalProfilePath) - return err - } - cp := j.LocalArtifacts.CreateChangedProfile() - defer cp.Close() - s := bufio.NewScanner(bytes.NewReader(p)) - s.Scan() - writeLine(cp, s.Text()) - - for s.Scan() { - for _, file := range changedFiles { - if strings.HasPrefix(s.Text(), file) { - writeLine(cp, s.Text()) - } - } - } - - return nil -} - -// writeLine writes a line in the given file, if the file pointer is not nil -func writeLine(file *os.File, content string) { - if file != nil { - fmt.Fprintln(file, content) - } -} - -// JobPrefixOnQiniu generates the prefix string of the job on qiniu -func (j *Job) JobPrefixOnQiniu() string { - return path.Join("pr-logs", "pull", j.Org+"_"+j.RepoName, j.PRNumStr, j.JobName, j.BuildId) -} - -// HtmlProfile generates the name of the profile html file -func (j *Job) HtmlProfile() string { - return fmt.Sprintf("%s-%s-pr%s-coverage.html", j.Org, j.RepoName, j.PRNumStr) -} - -// SetDeltaCovLinks set DeltaCovLinks to the job -func (j *Job) SetDeltaCovLinks(c cover.DeltaCovList) { - c.Sort() - for i := 0; i < len(c); i++ { - qnKey := path.Join(j.JobPrefixOnQiniu(), "artifacts", j.HtmlProfile()) - authQnKey := j.QiniuClient.GetAccessURL(qnKey, time.Hour*24*7) - c[i].SetLineCovLink(authQnKey + "#file" + strconv.Itoa(i)) - logrus.Printf("file %s html coverage link is: %s\n", c[i].FileName, c[i].GetLineCovLink()) - } -} - -// CreateChangedCovHtml create changed file related coverage html base on the local artifact -func (j *Job) CreateChangedCovHtml() error { - if j.LocalArtifacts.GetChangedProfileName() == "" { - logrus.Errorf("param LocalArtifacts.ChangedProfileName is empty") - } - pathProfileCov := j.LocalArtifacts.GetChangedProfileName() - pathHtmlCov := path.Join(os.Getenv("ARTIFACTS"), j.HtmlProfile()) - cmdTxt := fmt.Sprintf("go tool cover -html=%s -o %s", pathProfileCov, pathHtmlCov) - logrus.Printf("Running command '%s'\n", cmdTxt) - cmd := exec.Command("go", "tool", "cover", "-html="+pathProfileCov, "-o", pathHtmlCov) - stdOut, err := cmd.CombinedOutput() - if err != nil { - logrus.Printf("Error executing cmd: %v; combinedOutput=%s", err, stdOut) - } - return err -} - -func getFilesAndCovList(fullDiff bool, prComment github.PrComment, localP, baseP cover.CoverageList) (changedFiles []string, deltaCovList cover.DeltaCovList, err error) { - if !fullDiff { - // get github pull request changed files' name - var ghChangedFiles, err = prComment.GetPrChangedFiles() - if err != nil { - return nil, nil, fmt.Errorf("Get pull request changed file failed: %s", err.Error()) - } - if len(ghChangedFiles) == 0 { - logrus.Printf("0 files changed in github pull request, don't need to run coverage profile in presubmit.\n") - return nil, nil, nil - } - changedFiles = trimGhFileToProfile(ghChangedFiles) - - // calculate diff cov between local and remote profile - deltaCovList = cover.GetChFileDeltaCov(localP, baseP, changedFiles) - logrus.Printf("Get changed files and delta cover list success. ChangedFiles: [%+v], DeltaCovList: [%+v]", changedFiles, deltaCovList) - return changedFiles, deltaCovList, nil - } - deltaCovList = cover.GetDeltaCov(localP, baseP) - for _, d := range deltaCovList { - changedFiles = append(changedFiles, d.FileName) - } - logrus.Printf("Get all files and delta cover list success. Files: [%+v], DeltaCovList: [%+v]", changedFiles, deltaCovList) - return changedFiles, deltaCovList, nil -} diff --git a/pkg/prow/job_test.go b/pkg/prow/job_test.go deleted file mode 100644 index 2786c1c..0000000 --- a/pkg/prow/job_test.go +++ /dev/null @@ -1,380 +0,0 @@ -/* - Copyright 2020 Qiniu Cloud (qiniu.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 prow - -import ( - "context" - "errors" - "fmt" - "io/ioutil" - "os" - "path" - "testing" - "time" - - "github.com/sirupsen/logrus" - "github.com/stretchr/testify/assert" - - "github.com/qiniu/goc/pkg/cover" - "github.com/qiniu/goc/pkg/github" - "github.com/qiniu/goc/pkg/qiniu" -) - -var ( - defaultContent = `mode: atomic -qiniu.com/kodo/bd/bdgetter/source.go:19.118,22.2 2 0 -qiniu.com/kodo/bd/bdgetter/source.go:37.34,39.2 1 0 -qiniu.com/kodo/bd/pfd/locker/app/qboxbdlocker/main.go:50.2,53.52 4 1 -qiniu.com/kodo/bd/pfd/locker/bdlocker/locker.go:33.51,35.2 1 0` - defaultLocalPath = "local.cov" - defaultChangedPath = "changed.cov" -) - -type MockQnClient struct { - QiniuObjectHandleRes qiniu.ObjectHandle - ReadObjectRes []byte - ReadObjectErr error - ListAllRes []string - ListAllErr error - GetAccessURLRes string - GetArtifactDetailsRes *qiniu.LogHistoryTemplate - GetArtifactDetailsErr error - ListSubDirsRes []string - ListSubDirsErr error -} - -func (s *MockQnClient) QiniuObjectHandle(key string) qiniu.ObjectHandle { - return s.QiniuObjectHandleRes -} - -func (s *MockQnClient) ReadObject(key string) ([]byte, error) { - return s.ReadObjectRes, s.ReadObjectErr -} - -func (s *MockQnClient) ListAll(ctx context.Context, prefix string, delimiter string) ([]string, error) { - return s.ListAllRes, s.ListAllErr -} - -func (s *MockQnClient) GetAccessURL(key string, timeout time.Duration) string { - return s.GetAccessURLRes -} - -func (s *MockQnClient) GetArtifactDetails(key string) (*qiniu.LogHistoryTemplate, error) { - return s.GetArtifactDetailsRes, s.GetArtifactDetailsErr -} - -func (s *MockQnClient) ListSubDirs(prefix string) ([]string, error) { - return s.ListSubDirsRes, s.ListSubDirsErr -} - -type MockPrComment struct { - GetPrChangedFilesRes []string - GetPrChangedFilesErr error - PostCommentErr error - EraseHistoryCommentErr error - CreateGithubCommentErr error - CommentFlag string -} - -func (s *MockPrComment) GetPrChangedFiles() (files []string, err error) { - return s.GetPrChangedFilesRes, s.GetPrChangedFilesErr -} - -func (s *MockPrComment) PostComment(content, commentPrefix string) error { - return s.PostCommentErr -} - -func (s *MockPrComment) EraseHistoryComment(commentPrefix string) error { - return s.EraseHistoryCommentErr -} - -func (s *MockPrComment) CreateGithubComment(commentPrefix string, diffCovList cover.DeltaCovList) (err error) { - return s.CreateGithubCommentErr -} - -func (s *MockPrComment) GetCommentFlag() string { - return s.CommentFlag -} - -func TestTrimGhFileToProfile(t *testing.T) { - items := []struct { - inputFiles []string - expectFiles []string - }{ - { - inputFiles: []string{"src/qiniu.com/kodo/io/io/io_svr.go", "README.md"}, - expectFiles: []string{"qiniu.com/kodo/io/io/io_svr.go", "README.md"}, - }, - } - - for _, tc := range items { - f := trimGhFileToProfile(tc.inputFiles) - assert.Equal(t, f, tc.expectFiles) - } -} - -func setup(path, content string) { - err := ioutil.WriteFile(path, []byte(content), 0644) - if err != nil { - logrus.WithError(err).Fatalf("write file %s failed", path) - } -} - -func TestWriteChangedCov(t *testing.T) { - path := defaultLocalPath - savePath := qiniu.ChangedProfileName - content := defaultContent - changedFiles := []string{"qiniu.com/kodo/bd/pfd/locker/bdlocker/locker.go"} - expectContent := `mode: atomic -qiniu.com/kodo/bd/pfd/locker/bdlocker/locker.go:33.51,35.2 1 0 -` - - setup(path, content) - defer os.Remove(path) - defer os.Remove(savePath) - j := &Job{ - LocalProfilePath: path, - LocalArtifacts: &qiniu.ProfileArtifacts{ChangedProfileName: savePath}, - } - j.WriteChangedCov(changedFiles) - - r, err := ioutil.ReadFile(savePath) - if err != nil { - logrus.WithError(err).Fatalf("read file %s failed", path) - } - assert.Equal(t, string(r), expectContent) -} - -func TestRunPresubmitFulldiff(t *testing.T) { - //param - org := "qbox" - repo := "kodo" - prNum := "1" - buildId := "1266322425771986946" - jobName := "kodo-pull-integration-test" - robotName := "qiniu-bot" - githubCommentPrefix := "" - githubTokenPath := "token" - - //mock local profile - pwd, err := os.Getwd() - assert.NoError(t, err) - localPath := defaultLocalPath - localProfileContent := `mode: atomic -"qiniu.com/kodo/apiserver/server/main.go:32.49,33.13 1 30 -"qiniu.com/kodo/apiserver/server/main.go:42.49,43.13 1 0` - setup(localPath, localProfileContent) - defer os.Remove(path.Join(pwd, localPath)) - - // mock qiniu - conf := qiniu.Config{ - Bucket: "artifacts", - } - qc, router, _, teardown := qiniu.MockQiniuServer(&conf) - defer teardown() - qiniu.MockRouterAPI(router, localProfileContent, 0) - - ChangedProfilePath := "changed.cov" - defer os.Remove(path.Join(pwd, ChangedProfilePath)) - - //mock github client - setup(githubTokenPath, "") - defer os.Remove(path.Join(pwd, githubTokenPath)) - prClient := github.NewPrClient(githubTokenPath, org, repo, prNum, robotName, githubCommentPrefix) - - j := &Job{ - JobName: jobName, - Org: org, - RepoName: repo, - PRNumStr: prNum, - BuildId: buildId, - PostSubmitJob: "kodo-postsubmits-go-st-coverage", - PostSubmitCoverProfile: "filterd.cov", - LocalProfilePath: localPath, - LocalArtifacts: &qiniu.ProfileArtifacts{ChangedProfileName: ChangedProfilePath}, - QiniuClient: qc, - GithubComment: prClient, - FullDiff: true, - } - defer os.Remove(path.Join(os.Getenv("ARTIFACTS"), j.HtmlProfile())) - - err = j.RunPresubmit() - assert.NoError(t, err) -} - -func TestRunPresubmitError(t *testing.T) { - items := []struct { - prepare bool // prepare local profile - j Job - err string - }{ - { - prepare: false, - j: Job{ - LocalProfilePath: "unknown", - }, - err: "no such file or directory", - }, - { - prepare: true, - j: Job{ - LocalProfilePath: defaultLocalPath, - QiniuClient: &MockQnClient{}, - }, - }, - { - prepare: true, - j: Job{ - LocalProfilePath: defaultLocalPath, - QiniuClient: &MockQnClient{ListSubDirsErr: errors.New("mock error")}, - }, - err: "mock error", - }, - { - prepare: true, - j: Job{ - LocalProfilePath: defaultLocalPath, - QiniuClient: &MockProfileQnClient{}, - GithubComment: &MockPrComment{GetPrChangedFilesRes: []string{"qiniu.com/kodo/apiserver/server/main.go"}}, - FullDiff: true, - LocalArtifacts: &qiniu.ProfileArtifacts{ChangedProfileName: defaultChangedPath}, - }, - err: "", - }, - } - for _, tc := range items { - if tc.prepare { - path := defaultLocalPath - setup(path, defaultContent) - defer os.Remove(path) - defer os.Remove(defaultChangedPath) - } - err := tc.j.RunPresubmit() - if tc.err == "" { - assert.NoError(t, err) - } else { - assert.Contains(t, err.Error(), tc.err) - } - } -} - -type MockProfileQnClient struct { - *MockQnClient -} - -func (s *MockProfileQnClient) ListSubDirs(prefix string) ([]string, error) { - return []string{defaultContent}, nil -} - -func (s *MockProfileQnClient) ReadObject(key string) ([]byte, error) { - logrus.Info(key) - if key == "logs/1/finished.json" { - return []byte(`{"timestamp":1590750306,"passed":true,"result":"SUCCESS","repo-version":"76433418ea48aae57af028f9cb2fa3735ce08c7d"}`), nil - } - return []byte(""), nil -} - -func TestGetFilesAndCovList(t *testing.T) { - items := []struct { - fullDiff bool - prComment github.PrComment - localP cover.CoverageList - baseP cover.CoverageList - err string - lenFiles int - lenCovList int - }{ - { - fullDiff: true, - prComment: &MockPrComment{}, - localP: cover.CoverageList{ - {FileName: "qiniu.com/kodo/apiserver/server/main.go", NCoveredStmts: 2, NAllStmts: 2}, - {FileName: "qiniu.com/kodo/apiserver/server/test.go", NCoveredStmts: 2, NAllStmts: 2}, - }, - baseP: cover.CoverageList{ - {FileName: "qiniu.com/kodo/apiserver/server/main.go", NCoveredStmts: 1, NAllStmts: 2}, - {FileName: "qiniu.com/kodo/apiserver/server/test.go", NCoveredStmts: 1, NAllStmts: 2}, - }, - lenFiles: 2, - lenCovList: 2, - }, - { - fullDiff: false, - prComment: &MockPrComment{GetPrChangedFilesErr: errors.New("mock error")}, - err: "mock error", - }, - { - fullDiff: false, - prComment: &MockPrComment{}, - lenFiles: 0, - lenCovList: 0, - }, - { - fullDiff: false, - prComment: &MockPrComment{GetPrChangedFilesRes: []string{"qiniu.com/kodo/apiserver/server/main.go"}}, - localP: cover.CoverageList{ - {FileName: "qiniu.com/kodo/apiserver/server/main.go", NCoveredStmts: 2, NAllStmts: 2}, - {FileName: "qiniu.com/kodo/apiserver/server/test.go", NCoveredStmts: 2, NAllStmts: 2}, - }, - baseP: cover.CoverageList{ - {FileName: "qiniu.com/kodo/apiserver/server/main.go", NCoveredStmts: 1, NAllStmts: 2}, - {FileName: "qiniu.com/kodo/apiserver/server/test.go", NCoveredStmts: 1, NAllStmts: 2}, - }, - lenFiles: 1, - lenCovList: 1, - }, - } - - for i, tc := range items { - fmt.Println(i) - files, covList, err := getFilesAndCovList(tc.fullDiff, tc.prComment, tc.localP, tc.baseP) - if err != nil { - assert.Contains(t, err.Error(), tc.err) - } else { - assert.Equal(t, len(files), tc.lenFiles) - assert.Equal(t, len(covList), tc.lenCovList) - } - } -} - -func TestSetDeltaCovLinks(t *testing.T) { - covList := cover.DeltaCovList{{FileName: "file1", BasePer: "5%", NewPer: "5%", DeltaPer: "0"}} - j := &Job{ - QiniuClient: &MockQnClient{}, - } - j.SetDeltaCovLinks(covList) -} - -// functions to be done - -func TestRunPostsubmit(t *testing.T) { - j := &Job{} - err := j.RunPostsubmit() - assert.NoError(t, err) -} - -func TestRunPeriodic(t *testing.T) { - j := &Job{} - err := j.RunPeriodic() - assert.NoError(t, err) -} - -func TestFetch(t *testing.T) { - j := &Job{} - res := j.Fetch("buidID", "name") - assert.Equal(t, res, []byte{}) -} diff --git a/pkg/qiniu/client.go b/pkg/qiniu/client.go deleted file mode 100644 index e0c8918..0000000 --- a/pkg/qiniu/client.go +++ /dev/null @@ -1,254 +0,0 @@ -/* - Copyright 2020 Qiniu Cloud (qiniu.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 qiniu - -import ( - "context" - "fmt" - "io/ioutil" - "math/rand" - "net/http" - "regexp" - "strconv" - "strings" - "time" - - "github.com/qiniu/api.v7/v7/auth/qbox" - "github.com/qiniu/api.v7/v7/client" - "github.com/qiniu/api.v7/v7/storage" - "github.com/sirupsen/logrus" -) - -// Config store the credentials to connect with qiniu cloud -type Config struct { - Bucket string `json:"bucket"` - AccessKey string `json:"accessKey"` - SecretKey string `json:"secretKey"` - - // domain used to download files from qiniu cloud - Domain string `json:"domain"` -} - -// Client is the interface contains the operation with qiniu cloud -type Client interface { - QiniuObjectHandle(key string) ObjectHandle - ReadObject(key string) ([]byte, error) - ListAll(ctx context.Context, prefix string, delimiter string) ([]string, error) - GetAccessURL(key string, timeout time.Duration) string - GetArtifactDetails(key string) (*LogHistoryTemplate, error) - ListSubDirs(prefix string) ([]string, error) -} - -// QnClient for the operation with qiniu cloud -type QnClient struct { - cfg *Config - BucketManager *storage.BucketManager -} - -// NewClient creates a new QnClient to work with qiniu cloud -func NewClient(cfg *Config) *QnClient { - return &QnClient{ - cfg: cfg, - BucketManager: storage.NewBucketManager(qbox.NewMac(cfg.AccessKey, cfg.SecretKey), nil), - } -} - -// QiniuObjectHandle construct a object hanle to access file in qiniu -func (q *QnClient) QiniuObjectHandle(key string) ObjectHandle { - return &QnObjectHandle{ - key: key, - cfg: q.cfg, - bm: q.BucketManager, - mac: qbox.NewMac(q.cfg.AccessKey, q.cfg.SecretKey), - client: &client.Client{Client: http.DefaultClient}, - } -} - -// ReadObject to read all the content of key -func (q *QnClient) ReadObject(key string) ([]byte, error) { - objectHandle := q.QiniuObjectHandle(key) - reader, err := objectHandle.NewReader(context.Background()) - if err != nil { - return nil, fmt.Errorf("error getting qiniu artifact reader: %v", err) - } - defer reader.Close() - return ioutil.ReadAll(reader) -} - -// ListAll to list all the files with contains the expected prefix -func (q *QnClient) ListAll(ctx context.Context, prefix string, delimiter string) ([]string, error) { - var files []string - artifacts, err := q.listEntries(prefix, delimiter) - if err != nil { - return files, err - } - - for _, item := range artifacts { - files = append(files, item.Key) - } - - return files, nil -} - -// listEntries to list all the entries with contains the expected prefix -func (q *QnClient) listEntries(prefix string, delimiter string) ([]storage.ListItem, error) { - var marker string - var artifacts []storage.ListItem - - wait := []time.Duration{16, 32, 64, 128, 256, 256, 512, 512} - for i := 0; ; { - entries, _, nextMarker, hashNext, err := q.BucketManager.ListFiles(q.cfg.Bucket, prefix, delimiter, marker, 500) - if err != nil { - logrus.WithField("prefix", prefix).WithError(err).Error("Error accessing QINIU artifact.") - if i >= len(wait) { - return artifacts, fmt.Errorf("timed out: error accessing QINIU artifact: %v", err) - } - time.Sleep((wait[i] + time.Duration(rand.Intn(10))) * time.Millisecond) - i++ - continue - } - artifacts = append(artifacts, entries...) - - if hashNext { - marker = nextMarker - } else { - break - } - } - - return artifacts, nil -} - -// GetAccessURL return a url which can access artifact directly in qiniu -func (q *QnClient) GetAccessURL(key string, timeout time.Duration) string { - deadline := time.Now().Add(timeout).Unix() - return storage.MakePrivateURL(qbox.NewMac(q.cfg.AccessKey, q.cfg.SecretKey), q.cfg.Domain, key, deadline) -} - -// LogHistoryTemplate is the template of the log history -type LogHistoryTemplate struct { - BucketName string - KeyPath string - Items []logHistoryItem -} - -// logHistoryItem represents a log history item -type logHistoryItem struct { - Name string - Size string - Time string - Url string -} - -// GetArtifactDetails lists all artifacts available for the given job source -func (q *QnClient) GetArtifactDetails(key string) (*LogHistoryTemplate, error) { - tmpl := new(LogHistoryTemplate) - item := logHistoryItem{} - listStart := time.Now() - artifacts, err := q.listEntries(key, "") - if err != nil { - return tmpl, err - } - - for _, entry := range artifacts { - item.Name = splitKey(entry.Key, key) - item.Size = size(entry.Fsize) - item.Time = timeConv(entry.PutTime) - item.Url = q.GetAccessURL(entry.Key, time.Duration(time.Second*60*60)) - tmpl.Items = append(tmpl.Items, item) - } - - logrus.WithField("duration", time.Since(listStart).String()).Infof("Listed %d artifacts.", len(tmpl.Items)) - return tmpl, nil -} - -func splitKey(item, key string) string { - return strings.TrimPrefix(item, key) -} - -func size(fsize int64) string { - return strings.Join([]string{strconv.FormatInt(fsize, 10), "bytes"}, " ") -} - -func timeConv(ptime int64) string { - s := strconv.FormatInt(ptime, 10)[0:10] - t, err := strconv.ParseInt(s, 10, 64) - if err != nil { - logrus.Errorf("time string parse int error : %v", err) - return "" - } - tm := time.Unix(t, 0) - return tm.Format("2006-01-02 03:04:05 PM") -} - -// ListSubDirs list all the sub directions of the prefix string in qiniu client -func (q *QnClient) ListSubDirs(prefix string) ([]string, error) { - var dirs []string - var marker string - - wait := []time.Duration{16, 32, 64, 128, 256, 256, 512, 512} - for i := 0; ; { - // use rsf list v2 interface to get the sub folder based on the delimiter - entries, err := q.BucketManager.ListBucketContext(context.Background(), q.cfg.Bucket, prefix, "/", marker) - if err != nil { - logrus.WithField("prefix", prefix).WithError(err).Error("Error accessing QINIU artifact.") - if i >= len(wait) { - return dirs, fmt.Errorf("timed out: error accessing QINIU artifact: %v", err) - } - time.Sleep((wait[i] + time.Duration(rand.Intn(10))) * time.Millisecond) - i++ - continue - } - - for entry := range entries { - if entry.Dir != "" { - // entry.Dir should be like "logs/kodo-periodics-integration-test/1181915661132107776/" - // the sub folder is 1181915661132107776, also known as prowjob buildid. - buildId := getBuildId(entry.Dir) - if buildId != "" { - dirs = append(dirs, buildId) - } else { - logrus.Warnf("invalid dir format: %v", entry.Dir) - } - } - - marker = entry.Marker - } - - if marker != "" { - i = 0 - } else { - break - } - } - - return dirs, nil -} - -var nonPRLogsBuildIdSubffixRe = regexp.MustCompile("([0-9]+)/$") - -// extract the build number from dir path -// expect the dir as the following formats: -// 1. logs/kodo-periodics-integration-test/1181915661132107776/ -func getBuildId(dir string) string { - matches := nonPRLogsBuildIdSubffixRe.FindStringSubmatch(dir) - if len(matches) == 2 { - return matches[1] - } - - return "" -} diff --git a/pkg/qiniu/client_test.go b/pkg/qiniu/client_test.go deleted file mode 100644 index a8367a1..0000000 --- a/pkg/qiniu/client_test.go +++ /dev/null @@ -1,184 +0,0 @@ -/* - Copyright 2020 Qiniu Cloud (qiniu.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 qiniu - -import ( - "context" - "path" - "strings" - "testing" - - "github.com/stretchr/testify/assert" -) - -func TestGetBuildId(t *testing.T) { - type tc struct { - dir string - expected string - } - - tcs := []tc{ - {dir: "logs/kodo-periodics-integration-test/1181915661132107776/", expected: "1181915661132107776"}, - {dir: "logs/kodo-periodics-integration-test/1181915661132107776", expected: ""}, - {dir: "pr-logs/directory/WIP-qtest-pull-request-kodo-test/1181915661132107776/", expected: "1181915661132107776"}, - {dir: "pr-logs/directory/WIP-qtest-pull-request-kodo-test/1181915661132107776.txt", expected: ""}, - } - - for _, tc := range tcs { - got := getBuildId(tc.dir) - if tc.expected != got { - t.Errorf("getBuildId error, dir: %s, expect: %s, but got: %s", tc.dir, tc.expected, got) - } - } -} - -// test basic listEntries function -func TestListAllFiles(t *testing.T) { - conf := Config{ - Bucket: "artifacts", - } - qc, router, _, teardown := MockQiniuServer(&conf) - defer teardown() - prowJobName := "kodo-postsubmits-go-st-coverage" - dirOfJob := path.Join("logs", prowJobName) - prefix := dirOfJob + "/" - - MockRouterListAllAPI(router, 0) - listItems, err := qc.listEntries(prefix, "/") - - assert.Equal(t, err, nil) - assert.Equal(t, len(listItems), 1) - assert.Equal(t, listItems[0].Key, "logs/kodo-postsubmits-go-st-coverage/1181915661132107776/finished.json") -} - -// test basic listEntries function, recover after 3 times -func TestListAllFilesWithServerTimeoutAndRecover(t *testing.T) { - conf := Config{ - Bucket: "artifacts", - } - qc, router, _, teardown := MockQiniuServer(&conf) - defer teardown() - prowJobName := "kodo-postsubmits-go-st-coverage" - dirOfJob := path.Join("logs", prowJobName) - prefix := dirOfJob + "/" - - // recover after 3 times - MockRouterListAllAPI(router, 3) - listItems, err := qc.listEntries(prefix, "/") - - assert.Equal(t, err, nil) - assert.Equal(t, len(listItems), 1) - assert.Equal(t, listItems[0].Key, "logs/kodo-postsubmits-go-st-coverage/1181915661132107776/finished.json") -} - -// test basic listEntries function, never recover -func TestListAllFilesWithServerTimeout(t *testing.T) { - conf := Config{ - Bucket: "artifacts", - } - qc, router, _, teardown := MockQiniuServer(&conf) - defer teardown() - prowJobName := "kodo-postsubmits-go-st-coverage" - dirOfJob := path.Join("logs", prowJobName) - prefix := dirOfJob + "/" - - // never recover - MockRouterListAllAPI(router, 13) - _, err := qc.listEntries(prefix, "/") - - assert.Equal(t, strings.Contains(err.Error(), "timed out: error accessing QINIU artifact"), true) -} - -// test ListAll function -func TestListAllFilesWithContext(t *testing.T) { - conf := Config{ - Bucket: "artifacts", - } - qc, router, _, teardown := MockQiniuServer(&conf) - defer teardown() - prowJobName := "kodo-postsubmits-go-st-coverage" - dirOfJob := path.Join("logs", prowJobName) - prefix := dirOfJob + "/" - - MockRouterListAllAPI(router, 0) - listItems, err := qc.ListAll(context.Background(), prefix, "/") - - assert.Equal(t, err, nil) - assert.Equal(t, len(listItems), 1) - assert.Equal(t, listItems[0], "logs/kodo-postsubmits-go-st-coverage/1181915661132107776/finished.json") -} - -// test GetArtifactDetails function -func TestGetArtifactDetails(t *testing.T) { - conf := Config{ - Bucket: "artifacts", - } - qc, router, _, teardown := MockQiniuServer(&conf) - defer teardown() - prowJobName := "kodo-postsubmits-go-st-coverage" - dirOfJob := path.Join("logs", prowJobName) - prefix := dirOfJob + "/" - - MockRouterListAllAPI(router, 0) - tmpl, err := qc.GetArtifactDetails(prefix) - assert.Equal(t, err, nil) - assert.Equal(t, len(tmpl.Items), 1) - assert.Equal(t, tmpl.Items[0].Name, "1181915661132107776/finished.json") - assert.Equal(t, strings.Contains(tmpl.Items[0].Url, prowJobName), true) -} - -// test ListSubDirs function, recover after 3 times -func TestListSubDirsWithServerTimeoutAndRecover(t *testing.T) { - conf := Config{ - Bucket: "artifacts", - } - qc, router, _, teardown := MockQiniuServer(&conf) - defer teardown() - prowJobName := "kodo-postsubmits-go-st-coverage" - dirOfJob := path.Join("logs", prowJobName) - prefix := dirOfJob + "/" - localProfileContent := `mode: atomic -"qiniu.com/kodo/apiserver/server/main.go:32.49,33.13 1 30 -"qiniu.com/kodo/apiserver/server/main.go:42.49,43.13 1 0` - // recover after 3 times - MockRouterAPI(router, localProfileContent, 3) - listItems, err := qc.ListSubDirs(prefix) - - assert.Equal(t, err, nil) - assert.Equal(t, len(listItems), 1) - assert.Equal(t, listItems[0], "1181915661132107776") -} - -// test ListSubDirs function, never recover -func TestListSubDirsWithServerTimeout(t *testing.T) { - conf := Config{ - Bucket: "artifacts", - } - qc, router, _, teardown := MockQiniuServer(&conf) - defer teardown() - prowJobName := "kodo-postsubmits-go-st-coverage" - dirOfJob := path.Join("logs", prowJobName) - prefix := dirOfJob + "/" - localProfileContent := `mode: atomic -"qiniu.com/kodo/apiserver/server/main.go:32.49,33.13 1 30 -"qiniu.com/kodo/apiserver/server/main.go:42.49,43.13 1 0` - // never recover - MockRouterAPI(router, localProfileContent, 13) - _, err := qc.ListSubDirs(prefix) - - assert.Equal(t, strings.Contains(err.Error(), "timed out: error accessing QINIU artifact"), true) -} diff --git a/pkg/qiniu/mock.go b/pkg/qiniu/mock.go deleted file mode 100644 index c1a28f2..0000000 --- a/pkg/qiniu/mock.go +++ /dev/null @@ -1,162 +0,0 @@ -/* - Copyright 2020 Qiniu Cloud (qiniu.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 qiniu - -import ( - "fmt" - "net/http" - "net/http/httptest" - - "github.com/julienschmidt/httprouter" - "github.com/qiniu/api.v7/v7/storage" - "github.com/sirupsen/logrus" -) - -// MockQiniuServer simulate qiniu cloud for testing -func MockQiniuServer(config *Config) (client *QnClient, router *httprouter.Router, serverURL string, teardown func()) { - // router is the HTTP request multiplexer used with the test server. - router = httprouter.New() - - // server is a test HTTP server used to provide mock API responses. - server := httptest.NewServer(router) - - config.Domain = server.URL - client = NewClient(config) - client.BucketManager.Cfg = &storage.Config{ - RsfHost: server.URL, - } - - logrus.Infof("server url is: %s", server.URL) - return client, router, server.URL, server.Close -} - -// MockRouterAPI mocks qiniu /v2/list API. -// You need to provide a expected profile content. -// count controls the mocks qiniu server to error before 'count' times request. -func MockRouterAPI(router *httprouter.Router, profile string, count int) { - timeout := count - - // mock rsf /v2/list - router.HandlerFunc("POST", "/v2/list", func(w http.ResponseWriter, r *http.Request) { - logrus.Infof("request url is: %s", r.URL.String()) - - if timeout > 0 { - timeout-- - http.Error(w, "not found", http.StatusNotFound) - return - } - - fmt.Fprint(w, `{ - "item": { - "key": "logs/kodo-postsubmits-go-st-coverage/1181915661132107776/finished.json", - "hash": "FkBhdo9odL2Xjvu-YdwtDIw79fIL", - "fsize": 51523, - "mimeType": "application/octet-stream", - "putTime": 15909068578047958, - "type": 0, - "status": 0, - "md5": "e0bd20e97ea1c6a5e2480192ee3ae884" - }, - "marker": "", - "dir": "logs/kodo-postsubmits-go-st-coverage/1181915661132107776/" -}`) - }) - - // mock io get statusJSON file - router.HandlerFunc("GET", "/logs/kodo-postsubmits-go-st-coverage/1181915661132107776/finished.json", func(w http.ResponseWriter, r *http.Request) { - fmt.Fprint(w, `{"timestamp":1590750306,"passed":true,"result":"SUCCESS","repo-version":"76433418ea48aae57af028f9cb2fa3735ce08c7d"}`) - }) - - // mock io get remote coverage profile - router.HandlerFunc("GET", "/logs/kodo-postsubmits-go-st-coverage/1181915661132107776/artifacts/filterd.cov", func(w http.ResponseWriter, r *http.Request) { - fmt.Fprint(w, profile) - }) - -} - -// MockRouterListAllAPI mocks qiniu /list API. -// count controls the mocks qiniu server to error before 'count' times request. -func MockRouterListAllAPI(router *httprouter.Router, count int) { - timeout := count - // mock rsf /v2/list - router.HandlerFunc("POST", "/list", func(w http.ResponseWriter, r *http.Request) { - logrus.Infof("will respond after %v times", timeout) - logrus.Infof("request url is: %s", r.URL.String()) - - if timeout > 0 { - timeout-- - http.Error(w, "not found", http.StatusNotFound) - return - } - - fmt.Fprint(w, `{ - "items": [{ - "key": "logs/kodo-postsubmits-go-st-coverage/1181915661132107776/finished.json", - "hash": "FkBhdo9odL2Xjvu-YdwtDIw79fIL", - "fsize": 51523, - "mimeType": "application/octet-stream", - "putTime": 15909068578047958, - "type": 0, - "status": 0, - "md5": "e0bd20e97ea1c6a5e2480192ee3ae884" - }], - "marker": "", - "commonPrefixes": ["logs/kodo-postsubmits-go-st-coverage/1181915661132107776/"] -}`) - }) -} - -// MockPrivateDomainUrl mocks bucket domain /key, /timeout, /retry API. -// count controls the mocks qiniu server to error before 'count' times request. -func MockPrivateDomainUrl(router *httprouter.Router, count int) { - timeout1 := count - timeout2 := count - - router.HandlerFunc("GET", "/key", func(w http.ResponseWriter, r *http.Request) { - logrus.Infof("request url is: %s", r.URL.String()) - - fmt.Fprint(w, "mock server ok") - }) - - router.HandlerFunc("GET", "/timeout", func(w http.ResponseWriter, r *http.Request) { - logrus.Infof("request url is: %s", r.URL.String()) - - if timeout1 > 0 { - timeout1-- - http.Error(w, "not found", http.StatusNotFound) - return - } - - fmt.Fprint(w, "mock server ok") - }) - - router.HandlerFunc("GET", "/retry", func(w http.ResponseWriter, r *http.Request) { - logrus.Infof("request url is: %s", r.URL.String()) - - if timeout2 > 0 { - timeout2-- - if timeout2%2 == 0 { - http.Error(w, "not found", 571) - } else { - http.Error(w, "not found", 573) - } - return - } - - fmt.Fprint(w, "mock server ok") - }) -} diff --git a/pkg/qiniu/object.go b/pkg/qiniu/object.go deleted file mode 100644 index 81a8823..0000000 --- a/pkg/qiniu/object.go +++ /dev/null @@ -1,126 +0,0 @@ -/* - Copyright 2020 Qiniu Cloud (qiniu.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 qiniu - -import ( - "context" - "fmt" - "io" - "net/http" - "time" - - "github.com/qiniu/api.v7/v7/auth/qbox" - "github.com/qiniu/api.v7/v7/client" - "github.com/qiniu/api.v7/v7/storage" - "github.com/sirupsen/logrus" -) - -// ObjectHandle is the interface contains the operations on an object in a qiniu cloud bucket -type ObjectHandle interface { - NewReader(ctx context.Context) (io.ReadCloser, error) - NewRangeReader(ctx context.Context, offset, length int64) (io.ReadCloser, error) -} - -// QnObjectHandle provides operations on an object in a qiniu cloud bucket -type QnObjectHandle struct { - key string - cfg *Config - bm *storage.BucketManager - mac *qbox.Mac - client *client.Client -} - -// NewReader creates a reader to read the contents of the object. -// ErrObjectNotExist will be returned if the object is not found. -// The caller must call Close on the returned Reader when done reading. -func (o *QnObjectHandle) NewReader(ctx context.Context) (io.ReadCloser, error) { - return o.NewRangeReader(ctx, 0, -1) -} - -// NewRangeReader reads parts of an object, reading at most length bytes starting -// from the given offset. If length is negative, the object is read until the end. -func (o *QnObjectHandle) NewRangeReader(ctx context.Context, offset, length int64) (io.ReadCloser, error) { - verb := "GET" - if length == 0 { - verb = "HEAD" - } - - var res *http.Response - var err error - - err = runWithRetry(3, func() (bool, error) { - headers := http.Header{} - start := offset - if length < 0 && start >= 0 { - headers.Set("Range", fmt.Sprintf("bytes=%d-", start)) - } else if length > 0 { - // The end character isn't affected by how many bytes we have seen. - headers.Set("Range", fmt.Sprintf("bytes=%d-%d", start, offset+length-1)) - } - - deadline := time.Now().Add(time.Second * 60 * 10).Unix() - accessURL := storage.MakePrivateURL(o.mac, o.cfg.Domain, o.key, deadline) - res, err = o.client.DoRequest(ctx, verb, accessURL, headers) - if err != nil { - time.Sleep(time.Second) //TODO enhance - return true, err - } - - if res.StatusCode == http.StatusNotFound { - res.Body.Close() - return true, fmt.Errorf("qiniu storage: object not exists") - } - - return shouldRetry(res), nil - }) - - if err != nil { - return nil, err - } - - return res.Body, nil -} - -func runWithRetry(maxTry int, f func() (bool, error)) error { - var err error - for maxTry > 0 { - var needRetry bool - needRetry, err = f() // fix - needRetry, err := f(), err hides the outside error - if err != nil { - logrus.Warnf("err occurred: %v. try again", err) - } else if needRetry { - logrus.Warn("results do not meet the expectation. try again") - } else { - break - } - time.Sleep(time.Millisecond * 100) - maxTry = maxTry - 1 - } - - return err -} - -func shouldRetry(res *http.Response) bool { - - // 571 and 573 mean the request was limited by cloud storage because of concurrency count exceed - // so it's better to retry after a while - if res.StatusCode == 571 || res.StatusCode == 573 { - return true - } - - return false -} diff --git a/pkg/qiniu/object_test.go b/pkg/qiniu/object_test.go deleted file mode 100644 index f6d8427..0000000 --- a/pkg/qiniu/object_test.go +++ /dev/null @@ -1,138 +0,0 @@ -/* - Copyright 2020 Qiniu Cloud (qiniu.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 qiniu - -import ( - "context" - "fmt" - "io/ioutil" - "net/http" - "testing" - - "github.com/qiniu/api.v7/v7/auth/qbox" - "github.com/qiniu/api.v7/v7/client" - "github.com/stretchr/testify/assert" -) - -// test NewRangeReader logic -func TestNewRangeReader(t *testing.T) { - cfg := &Config{ - Bucket: "artifacts", - AccessKey: "ak", - SecretKey: "sk", - } - _, router, serverUrl, teardown := MockQiniuServer(cfg) - defer teardown() - cfg.Domain = serverUrl - - MockPrivateDomainUrl(router, 0) - - oh := &QnObjectHandle{ - key: "key", - cfg: cfg, - bm: nil, - mac: qbox.NewMac(cfg.AccessKey, cfg.SecretKey), - client: &client.Client{Client: http.DefaultClient}, - } - - // test read unlimited - body, err := oh.NewRangeReader(context.Background(), 0, -1) - assert.Equal(t, err, nil) - - bodyBytes, err := ioutil.ReadAll(body) - assert.NoError(t, err) - assert.Equal(t, string(bodyBytes), "mock server ok") - - // test with HEAD method - body, err = oh.NewRangeReader(context.Background(), 0, 0) - assert.Equal(t, err, nil) - - bodyBytes, err = ioutil.ReadAll(body) - assert.NoError(t, err) - assert.Equal(t, string(bodyBytes), "") - -} - -// test retry logic -func TestNewRangeReaderWithTimeoutAndRecover(t *testing.T) { - cfg := &Config{ - Bucket: "artifacts", - AccessKey: "ak", - SecretKey: "sk", - } - _, router, serverUrl, teardown := MockQiniuServer(cfg) - defer teardown() - cfg.Domain = serverUrl - - MockPrivateDomainUrl(router, 2) - - oh := &QnObjectHandle{ - key: "key", - cfg: cfg, - bm: nil, - mac: qbox.NewMac(cfg.AccessKey, cfg.SecretKey), - client: &client.Client{Client: http.DefaultClient}, - } - - // test with timeout - oh.key = "timeout" - body, err := oh.NewRangeReader(context.Background(), 0, 10) - assert.Equal(t, err, nil) - - bodyBytes, err := ioutil.ReadAll(body) - assert.NoError(t, err) - assert.Equal(t, string(bodyBytes), "mock server ok") - - // test with retry with statuscode=571, 573 - oh.key = "retry" - body, err = oh.NewRangeReader(context.Background(), 0, 10) - assert.Equal(t, err, nil) - - bodyBytes, err = ioutil.ReadAll(body) - assert.NoError(t, err) - assert.Equal(t, string(bodyBytes), "mock server ok") -} - -// test retry logic -func TestNewRangeReaderWithTimeoutNoRecover(t *testing.T) { - cfg := &Config{ - Bucket: "artifacts", - AccessKey: "ak", - SecretKey: "sk", - } - _, router, serverUrl, teardown := MockQiniuServer(cfg) - defer teardown() - cfg.Domain = serverUrl - - MockPrivateDomainUrl(router, 12) - - oh := &QnObjectHandle{ - key: "key", - cfg: cfg, - bm: nil, - mac: qbox.NewMac(cfg.AccessKey, cfg.SecretKey), - client: &client.Client{Client: http.DefaultClient}, - } - - // test with timeout - oh.key = "timeout" - _, err := oh.NewRangeReader(context.Background(), 0, -1) - assert.Equal(t, err, fmt.Errorf("qiniu storage: object not exists")) - - // bodyBytes, err := ioutil.ReadAll(body) - // assert.Equal(t, string(bodyBytes), "mock server ok") -} diff --git a/pkg/qiniu/qnPresubmit.go b/pkg/qiniu/qnPresubmit.go deleted file mode 100644 index 4aedf9e..0000000 --- a/pkg/qiniu/qnPresubmit.go +++ /dev/null @@ -1,146 +0,0 @@ -/* - Copyright 2020 Qiniu Cloud (qiniu.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 qiniu - -import ( - "encoding/json" - "fmt" - "os" - "path" - "sort" - "strconv" - - log "github.com/sirupsen/logrus" -) - -const ( - //statusJSON is the JSON file that stores build success info - statusJSON = "finished.json" - - // ArtifactsDirName is the name of directory defined in prow to store test artifacts - ArtifactsDirName = "artifacts" - - //PostSubmitCoverProfile represents the default output coverage file generated in prow environment - PostSubmitCoverProfile = "filtered.cov" - - //ChangedProfileName represents the default changed coverage profile based on files changed in Pull Request - ChangedProfileName = "changed-file-profile.cov" -) - -// sortBuilds converts all build from str to int and sorts all builds in descending order and -// returns the sorted slice -func sortBuilds(strBuilds []string) []int { - var res []int - for _, buildStr := range strBuilds { - num, err := strconv.Atoi(buildStr) - if err != nil { - log.Printf("Non-int build number found: '%s'", buildStr) - } else { - res = append(res, num) - } - } - sort.Sort(sort.Reverse(sort.IntSlice(res))) - return res -} - -type finishedStatus struct { - Timestamp int - Passed bool -} - -func isBuildSucceeded(jsonText []byte) bool { - var status finishedStatus - err := json.Unmarshal(jsonText, &status) - return err == nil && status.Passed -} - -// FindBaseProfileFromQiniu finds the coverage profile file from the latest healthy build -// stored in given gcs directory -func FindBaseProfileFromQiniu(qc Client, prowJobName, covProfileName string) ([]byte, error) { - dirOfJob := path.Join("logs", prowJobName) - prefix := dirOfJob + "/" - strBuilds, err := qc.ListSubDirs(prefix) - if err != nil { - return nil, fmt.Errorf("error listing qiniu objects, prowjob:%v, err:%v", prowJobName, err) - } - if len(strBuilds) == 0 { - log.Printf("no cover profiles found from remote, do nothing") - return nil, nil - } - log.Printf("total sub dirs: %d", len(strBuilds)) - - builds := sortBuilds(strBuilds) - profilePath := "" - for _, build := range builds { - buildDirPath := path.Join(dirOfJob, strconv.Itoa(build)) - dirOfStatusJSON := path.Join(buildDirPath, statusJSON) - - statusText, err := qc.ReadObject(dirOfStatusJSON) - if err != nil { - log.Printf("Cannot read finished.json (%s) ", dirOfStatusJSON) - } else if isBuildSucceeded(statusText) { - artifactsDirPath := path.Join(buildDirPath, ArtifactsDirName) - profilePath = path.Join(artifactsDirPath, covProfileName) - break - } - } - if profilePath == "" { - log.Printf("no cover profiles found from remote job %s, do nothing", prowJobName) - return nil, nil - } - - log.Printf("base cover profile path: %s", profilePath) - return qc.ReadObject(profilePath) -} - -// Artifacts is the interface of the rule to store test artifacts in prow -type Artifacts interface { - ProfilePath() string - CreateChangedProfile() *os.File - GetChangedProfileName() string -} - -// ProfileArtifacts presents the rule to store test artifacts in prow -type ProfileArtifacts struct { - Directory string - ProfileName string - ChangedProfileName string // create temporary to save changed file related coverage profile -} - -// ProfilePath returns a full path for profile -func (a *ProfileArtifacts) ProfilePath() string { - return path.Join(a.Directory, a.ProfileName) -} - -// CreateChangedProfile creates a profile in order to store the most related files based on Github Pull Request -func (a *ProfileArtifacts) CreateChangedProfile() *os.File { - if a.ChangedProfileName == "" { - log.Fatalf("param Artifacts.ChangedProfileName should not be empty") - } - p, err := os.Create(a.ChangedProfileName) - log.Printf("os create: %s", a.ChangedProfileName) - if err != nil { - log.Fatalf("file(%s) create failed: %v", a.ChangedProfileName, err) - } - - return p -} - -// GetChangedProfileName get ChangedProfileName of the ProfileArtifacts -func (a *ProfileArtifacts) GetChangedProfileName() string { - return a.ChangedProfileName -} diff --git a/pkg/qiniu/qnPresubmit_test.go b/pkg/qiniu/qnPresubmit_test.go deleted file mode 100644 index a4b1680..0000000 --- a/pkg/qiniu/qnPresubmit_test.go +++ /dev/null @@ -1,70 +0,0 @@ -/* - Copyright 2020 Qiniu Cloud (qiniu.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 qiniu - -import ( - "os" - "testing" - - "github.com/stretchr/testify/assert" -) - -func TestFindBaseProfileFromQiniu(t *testing.T) { - conf := Config{ - Bucket: "artifacts", - } - qc, router, _, teardown := MockQiniuServer(&conf) - defer teardown() - prowJobName := "kodo-postsubmits-go-st-coverage" - covProfileName := "filterd.cov" - mockProfileContent := `mode: atomic -"qiniu.com/kodo/apiserver/server/main.go:32.49,33.13 1 30 -"qiniu.com/kodo/apiserver/server/main.go:42.49,43.13 1 0` - - MockRouterAPI(router, mockProfileContent, 0) - getProfile, err := FindBaseProfileFromQiniu(qc, prowJobName, covProfileName) - assert.Equal(t, err, nil) - assert.Equal(t, string(getProfile), mockProfileContent) -} - -func TestArtifacts_ProfilePath(t *testing.T) { - p := &ProfileArtifacts{ - Directory: "directory/", - ProfileName: "profile", - } - profilePath := p.ProfilePath() - assert.Equal(t, profilePath, "directory/profile") -} - -func TestProfileArtifacts_CreateChangedProfile(t *testing.T) { - p := &ProfileArtifacts{ - ChangedProfileName: "test.cov", - } - file := p.CreateChangedProfile() - file.Close() - defer os.Remove(p.ChangedProfileName) - _, err := os.Stat(p.ChangedProfileName) - assert.NoError(t, err) -} - -func TestProfileArtifacts_GetChangedProfileName(t *testing.T) { - p := &ProfileArtifacts{ - ChangedProfileName: "change.cov", - } - name := p.GetChangedProfileName() - assert.Equal(t, name, "change.cov") -} diff --git a/pkg/server/api.go b/pkg/server/api.go new file mode 100644 index 0000000..f98321b --- /dev/null +++ b/pkg/server/api.go @@ -0,0 +1,202 @@ +package server + +import ( + "bytes" + "net/http" + "sync" + "time" + + "github.com/gin-gonic/gin" + "github.com/qiniu/goc/v2/pkg/log" + "golang.org/x/tools/cover" + "k8s.io/test-infra/gopherage/pkg/cov" +) + +// listAgents return all service informations +func (gs *gocServer) listAgents(c *gin.Context) { + agents := make([]*gocCoveredAgent, 0) + + gs.rpcAgents.Range(func(key, value interface{}) bool { + agent, ok := value.(*gocCoveredAgent) + if !ok { + return false + } + agents = append(agents, agent) + return true + }) + + c.JSON(http.StatusOK, gin.H{ + "items": agents, + }) +} + +// getProfiles get and merge all agents' informations +// +// it is synchronous +func (gs *gocServer) getProfiles(c *gin.Context) { + var mu sync.Mutex + var wg sync.WaitGroup + + mergedProfiles := make([][]*cover.Profile, 0) + + gs.rpcAgents.Range(func(key, value interface{}) bool { + agent, ok := value.(*gocCoveredAgent) + if !ok { + return false + } + + wg.Add(1) + // 并发 rpc,且每个 rpc 设超时时间 10 second + go func() { + defer wg.Done() + + timeout := time.Duration(10 * time.Second) + done := make(chan error, 1) + + var req ProfileReq = "getprofile" + var res ProfileRes + go func() { + err := agent.rpc.Call("GocAgent.GetProfile", req, &res) + if err != nil { + log.Errorf("fail to get profile from: %v, reasson: %v. let's close the connection", agent.Id, err) + } + done <- err + }() + + select { + // rpc 超时 + case <-time.After(timeout): + log.Warnf("rpc call timeout: %v", agent.Hostname) + // 关闭链接 + agent.once.Do(func() { + close(agent.exitCh) + }) + case err := <-done: + // 调用 rpc 发生错误 + if err != nil { + // 关闭链接 + agent.once.Do(func() { + close(agent.exitCh) + }) + } + } + // append profile + profile, err := convertProfile([]byte(res)) + if err != nil { + log.Errorf("fail to convert the received profile from: %v, reasson: %v. let's close the connection", agent.Id, err) + // 关闭链接 + agent.once.Do(func() { + close(agent.exitCh) + }) + return + } + mu.Lock() + defer mu.Unlock() + mergedProfiles = append(mergedProfiles, profile) + }() + + return true + }) + + // 一直等待并发的 rpc 都回应 + wg.Wait() + + merged, err := cov.MergeMultipleProfiles(mergedProfiles) + if err != nil { + c.JSON(http.StatusInternalServerError, gin.H{ + "msg": err.Error(), + }) + return + } + + var buff bytes.Buffer + err = cov.DumpProfile(merged, &buff) + if err != nil { + c.JSON(http.StatusInternalServerError, gin.H{ + "msg": err.Error(), + }) + return + } + + c.JSON(http.StatusOK, gin.H{ + "profile": buff.String(), + }) +} + +// resetProfiles reset all profiles in agent +// +// it is async, the function will return immediately +func (gs *gocServer) resetProfiles(c *gin.Context) { + gs.rpcAgents.Range(func(key, value interface{}) bool { + agent, ok := value.(gocCoveredAgent) + if !ok { + return false + } + + var req ProfileReq = "resetprofile" + var res ProfileRes + go func() { + err := agent.rpc.Call("GocAgent.ResetProfile", req, &res) + if err != nil { + log.Errorf("fail to reset profile from: %v, reasson: %v. let's close the connection", agent.Id, err) + // 关闭链接 + agent.once.Do(func() { + close(agent.exitCh) + }) + } + }() + + return true + }) +} + +// watchProfileUpdate watch the profile change +// +// any profile change will be updated on this websocket connection. +func (gs *gocServer) watchProfileUpdate(c *gin.Context) { + // upgrade to websocket + ws, err := gs.upgrader.Upgrade(c.Writer, c.Request, nil) + if err != nil { + log.Errorf("fail to establish websocket connection with watch client: %v", err) + c.JSON(http.StatusInternalServerError, nil) + } + + log.Infof("watch client connected") + + id := time.Now().String() + gwc := &gocWatchClient{ + ws: ws, + exitCh: make(chan int), + } + gs.watchClients.Store(id, gwc) + // send close msg and close ws connection + defer func() { + gs.watchClients.Delete(id) + ws.Close() + gwc.once.Do(func() { close(gwc.exitCh) }) + log.Infof("watch client disconnected") + }() + + // set pong handler + ws.SetReadDeadline(time.Now().Add(PongWait)) + ws.SetPongHandler(func(string) error { + ws.SetReadDeadline(time.Now().Add(PongWait)) + return nil + }) + + // set ping goroutine to ping every PingWait time + go func() { + ticker := time.NewTicker(PingWait) + defer ticker.Stop() + + for range ticker.C { + if err := gs.wsping(ws, PongWait); err != nil { + break + } + } + + gwc.once.Do(func() { close(gwc.exitCh) }) + }() + + <-gwc.exitCh +} diff --git a/pkg/server/common.go b/pkg/server/common.go new file mode 100644 index 0000000..5243e39 --- /dev/null +++ b/pkg/server/common.go @@ -0,0 +1,85 @@ +package server + +import ( + "io" + "time" + + "github.com/gorilla/websocket" +) + +const ( + PongWait = 10 * time.Second + PingWait = 5 * time.Second +) + +type ProfileReq string + +type ProfileRes string + +func (gs *gocServer) wsping(ws *websocket.Conn, deadline time.Duration) error { + return ws.WriteControl(websocket.PingMessage, []byte{}, time.Now().Add(deadline)) +} + +func (gs *gocServer) wsclose(ws *websocket.Conn, deadline time.Duration) error { + return ws.WriteControl(websocket.CloseMessage, []byte{}, time.Now().Add(deadline)) +} + +type ReadWriteCloser struct { + ws *websocket.Conn + r io.Reader + w io.WriteCloser +} + +func (rwc *ReadWriteCloser) Read(p []byte) (n int, err error) { + if rwc.r == nil { + var _ int + _, rwc.r, err = rwc.ws.NextReader() + if err != nil { + return 0, err + } + } + for n = 0; n < len(p); { + var m int + m, err = rwc.r.Read(p[n:]) + n += m + if err == io.EOF { + // done + rwc.r = nil + break + } + // ??? + if err != nil { + break + } + } + return +} + +func (rwc *ReadWriteCloser) Write(p []byte) (n int, err error) { + if rwc.w == nil { + rwc.w, err = rwc.ws.NextWriter(websocket.TextMessage) + if err != nil { + return 0, err + } + } + for n = 0; n < len(p); { + var m int + m, err = rwc.w.Write(p) + n += m + if err != nil { + break + } + } + if err != nil || n == len(p) { + err = rwc.Close() + } + return +} + +func (rwc *ReadWriteCloser) Close() (err error) { + if rwc.w != nil { + err = rwc.w.Close() + rwc.w = nil + } + return err +} diff --git a/pkg/server/rpcstream.go b/pkg/server/rpcstream.go new file mode 100644 index 0000000..9ef4227 --- /dev/null +++ b/pkg/server/rpcstream.go @@ -0,0 +1,119 @@ +package server + +import ( + "crypto/sha256" + "fmt" + "net/http" + "net/rpc" + "net/rpc/jsonrpc" + "time" + + "github.com/gin-gonic/gin" + "github.com/qiniu/goc/v2/pkg/log" +) + +// serveRpcStream holds connection between goc server and agent. +// +// 1. goc server 作为 rpc 客户端 +// +// 2. 每个链接的 goc agent 作为 rpc 服务端 +func (gs *gocServer) serveRpcStream(c *gin.Context) { + // 检查插桩服务上报的信息 + remoteIP, _ := c.RemoteIP() + hostname := c.Query("hostname") + pid := c.Query("pid") + cmdline := c.Query("cmdline") + + if hostname == "" || pid == "" || cmdline == "" { + c.JSON(http.StatusBadRequest, gin.H{ + "msg": "missing some params", + }) + return + } + // 计算插桩服务 id + agentId := gs.generateAgentId(remoteIP.String(), hostname, cmdline, pid) + // 检查 id 是否重复 + if _, ok := gs.rpcAgents.Load(agentId); ok { + c.JSON(http.StatusBadRequest, gin.H{ + "msg": "the rpc agent already exists", + }) + return + } + + gocA := &gocCoveredAgent{ + RemoteIP: remoteIP.String(), + Hostname: hostname, + Pid: pid, + CmdLine: cmdline, + exitCh: make(chan int), + } + + // upgrade to websocket + ws, err := gs.upgrader.Upgrade(c.Writer, c.Request, nil) + if err != nil { + log.Errorf("fail to establish websocket connection with rpc agent: %v", err) + c.JSON(http.StatusInternalServerError, nil) + } + + // send close msg and close ws connection + defer func() { + deadline := 1 * time.Second + // 发送 close msg + gs.wsclose(ws, deadline) + time.Sleep(deadline) + // 从维护的 websocket 链接字典中移除 + gs.rpcAgents.Delete(agentId) + ws.Close() + log.Infof("close rpc connection, %v", hostname) + }() + + // set pong handler + ws.SetReadDeadline(time.Now().Add(PongWait)) + ws.SetPongHandler(func(string) error { + ws.SetReadDeadline(time.Now().Add(PongWait)) + return nil + }) + + // set ping goroutine to ping every PingWait time + go func() { + ticker := time.NewTicker(PingWait) + defer ticker.Stop() + + for range ticker.C { + if err := gs.wsping(ws, PongWait); err != nil { + log.Errorf("rpc ping to %v failed: %v", hostname, err) + break + } + } + + gocA.once.Do(func() { + close(gocA.exitCh) + }) + }() + + log.Infof("one rpc agent established, %v, cmdline: %v, pid: %v, hostname: %v", ws.RemoteAddr(), cmdline, pid, hostname) + // new rpc agent + // 在这里 websocket server 作为 rpc 的客户端, + // 发送 rpc 请求, + // 由被插桩服务返回 rpc 应答 + rwc := &ReadWriteCloser{ws: ws} + codec := jsonrpc.NewClientCodec(rwc) + + gocA.rpc = rpc.NewClientWithCodec(codec) + gocA.Id = string(agentId) + gs.rpcAgents.Store(agentId, gocA) + // wait for exit + <-gocA.exitCh +} + +// generateAgentId generate id based on agent's meta infomation +func (gs *gocServer) generateAgentId(args ...string) gocCliendId { + var path string + for _, arg := range args { + path += arg + } + sum := sha256.Sum256([]byte(path)) + h := fmt.Sprintf("%x", sum[:6]) + + return gocCliendId(h) +} diff --git a/pkg/server/server.go b/pkg/server/server.go new file mode 100644 index 0000000..cf796b1 --- /dev/null +++ b/pkg/server/server.go @@ -0,0 +1,79 @@ +package server + +import ( + "net/http" + "net/rpc" + "sync" + "time" + + "github.com/gin-gonic/gin" + "github.com/gorilla/websocket" +) + +// gocServer represents a goc server +type gocServer struct { + port int + storePath string + upgrader websocket.Upgrader + + rpcAgents sync.Map + watchAgents sync.Map + watchCh chan []byte + watchClients sync.Map +} + +type gocCliendId string + +// gocCoveredAgent represents a covered client +type gocCoveredAgent struct { + Id string `json:"id"` + RemoteIP string `json:"remoteip"` + Hostname string `json:"hostname"` + CmdLine string `json:"cmdline"` + Pid string `json:"pid"` + rpc *rpc.Client `json:"-"` + + exitCh chan int `json:"-"` + once sync.Once `json:"-"` // 保护 close(exitCh) 只执行一次 +} + +// api 客户端,不是 agent +type gocWatchClient struct { + ws *websocket.Conn + exitCh chan int + once sync.Once +} + +func RunGocServerUntilExit(host string) { + gs := gocServer{ + storePath: "", + upgrader: websocket.Upgrader{ + ReadBufferSize: 4096, + WriteBufferSize: 4096, + HandshakeTimeout: 45 * time.Second, + CheckOrigin: func(r *http.Request) bool { + return true + }, + }, + watchCh: make(chan []byte, 4096), + } + + r := gin.Default() + v2 := r.Group("/v2") + { + v2.GET("/cover/profile", gs.getProfiles) + v2.DELETE("/cover/profile", gs.resetProfiles) + v2.GET("/rpcagents", gs.listAgents) + v2.GET("/watchagents", nil) + + v2.GET("/cover/ws/watch", gs.watchProfileUpdate) + + // internal use only + v2.GET("/internal/ws/rpcstream", gs.serveRpcStream) + v2.GET("/internal/ws/watchstream", gs.serveWatchInternalStream) + } + + go gs.watchLoop() + + r.Run(host) +} diff --git a/pkg/server/util.go b/pkg/server/util.go new file mode 100644 index 0000000..f0bfc95 --- /dev/null +++ b/pkg/server/util.go @@ -0,0 +1,28 @@ +package server + +import ( + "bytes" + "fmt" + "io" + "io/ioutil" + "os" + + "golang.org/x/tools/cover" +) + +func convertProfile(p []byte) ([]*cover.Profile, error) { + // Annoyingly, ParseProfiles only accepts a filename, so we have to write the bytes to disk + // so it can read them back. + // We could probably also just give it /dev/stdin, but that'll break on Windows. + tf, err := ioutil.TempFile("", "") + if err != nil { + return nil, fmt.Errorf("failed to create temp file, err: %v", err) + } + defer tf.Close() + defer os.Remove(tf.Name()) + if _, err := io.Copy(tf, bytes.NewReader(p)); err != nil { + return nil, fmt.Errorf("failed to copy data to temp file, err: %v", err) + } + + return cover.ParseProfiles(tf.Name()) +} diff --git a/pkg/server/watchstream.go b/pkg/server/watchstream.go new file mode 100644 index 0000000..02af6c7 --- /dev/null +++ b/pkg/server/watchstream.go @@ -0,0 +1,97 @@ +package server + +import ( + "net/http" + "time" + + "github.com/gin-gonic/gin" + "github.com/gorilla/websocket" + "github.com/qiniu/goc/v2/pkg/log" +) + +func (gs *gocServer) serveWatchInternalStream(c *gin.Context) { + // 检查插桩服务上报的信息 + remoteIP, _ := c.RemoteIP() + hostname := c.Query("hostname") + pid := c.Query("pid") + cmdline := c.Query("cmdline") + + if hostname == "" || pid == "" || cmdline == "" { + c.JSON(http.StatusBadRequest, gin.H{ + "msg": "missing some params", + }) + return + } + // 计算插桩服务 id + agentId := gs.generateAgentId(remoteIP.String(), hostname, cmdline, pid) + // 检查 id 是否重复 + if _, ok := gs.watchAgents.Load(agentId); ok { + c.JSON(http.StatusBadRequest, gin.H{ + "msg": "the watch agent already exist", + }) + return + } + // upgrade to websocket + ws, err := gs.upgrader.Upgrade(c.Writer, c.Request, nil) + if err != nil { + log.Errorf("fail to establish websocket connection with watch agent: %v", err) + c.JSON(http.StatusInternalServerError, nil) + } + + // send close msg and close ws connection + defer func() { + gs.watchAgents.Delete(agentId) + ws.Close() + log.Infof("close watch connection, %v", hostname) + }() + + // set pong handler + ws.SetReadDeadline(time.Now().Add(PongWait)) + ws.SetPongHandler(func(string) error { + ws.SetReadDeadline(time.Now().Add(PongWait)) + return nil + }) + + // set ping goroutine to ping every PingWait time + go func() { + ticker := time.NewTicker(PingWait) + defer ticker.Stop() + + for range ticker.C { + if err := gs.wsping(ws, PongWait); err != nil { + log.Errorf("watch ping to %v failed: %v", hostname, err) + break + } + } + }() + + log.Infof("one watch agent established, %v, cmdline: %v, pid: %v, hostname: %v", ws.RemoteAddr(), cmdline, pid, hostname) + + for { + mt, message, err := ws.ReadMessage() + if err != nil { + log.Errorf("read from %v: %v", hostname, err) + break + } + if mt == websocket.TextMessage { + gs.watchCh <- message + } + } +} + +func (gs *gocServer) watchLoop() { + for { + msg := <-gs.watchCh + gs.watchClients.Range(func(key, value interface{}) bool { + // 这里是客户端的 ws 连接,不是 agent ws 连接 + gwc := value.(*gocWatchClient) + err := gwc.ws.WriteMessage(websocket.TextMessage, msg) + if err != nil { + gwc.ws.Close() + gwc.once.Do(func() { close(gwc.exitCh) }) + } + + return true + }) + } +} diff --git a/pkg/watch/watch.go b/pkg/watch/watch.go new file mode 100644 index 0000000..4177260 --- /dev/null +++ b/pkg/watch/watch.go @@ -0,0 +1,27 @@ +package watch + +import ( + "fmt" + + "github.com/gorilla/websocket" + "github.com/qiniu/goc/v2/pkg/config" + "github.com/qiniu/goc/v2/pkg/log" +) + +func Watch() { + watchUrl := fmt.Sprintf("ws://%v/v2/cover/ws/watch", config.GocConfig.Host) + c, _, err := websocket.DefaultDialer.Dial(watchUrl, nil) + if err != nil { + log.Fatalf("cannot connect to goc server: %v", err) + } + defer c.Close() + + for { + _, message, err := c.ReadMessage() + if err != nil { + log.Fatalf("cannot read message: %v", err) + } + + log.Infof("profile update: %v", string(message)) + } +} diff --git a/tests/README.md b/tests/README.md deleted file mode 100644 index 0bb93d4..0000000 --- a/tests/README.md +++ /dev/null @@ -1,51 +0,0 @@ -# How to write goc e2e test cases - -Current goc e2e test is based on the [bats-core](https://github.com/bats-core/bats-core) framework, you should read its document first. - -## Local dev requirements - -* [bats-core](https://github.com/bats-core/bats-core) -* install `goc` to `PATH` -* build `goc` with `goc`, generate the binary `gocc`, install `gocc` to `PATH` - -## Test goc - -First of all, you should start a `goc server` in `setup_file` function from the backend, - -``` -setup_file() { - goc server 3>&- & - GOC_PID=$! - sleep 2 - goc init -} -``` - -According to [this](https://github.com/bats-core/bats-core/blob/master/README.md#file-descriptor-3-read-this-if-bats-hangs), you should turn off the file descriptor 3 for the long-running backend job. Then you can write any `goc` subcommand. Remember to kill the `$GOC_PID` in the `teardown_file` function. - -## Test covered goc - gocc - -We also need to test with the covered gocc in order to get coverage reports. - -Most gocc test cases share the same structure, here is the common flow diagram: - -``` - (1) (2) - (wait_profile_backend "xxx" &) --> wait ci-sync exist --> (goc profile -o filtered.cov)-- - | | - | | - | (4) | - --(gocc --debugcisyncfile ci-sync) --> finish, write ci-sync --> sleep 5; exit |(5) - | | | - | (3) (6) | | - |------------------------>(goc server &) --------------------------------| | - | | - --------------------------------------------------------- -``` - -1. start the `wait_profile_backend` in the background. -2. `wait_profile_backend` will block until the file `ci-sync.bak` exists. -3. the covered `gocc` subcommand start and register to the `goc server`. -4. the covered `gocc` subcommand run its own logic until finish, as we add the `--debugcisyncfile ci-sync` flag, it will write a file called `ci-sync`, and wait 5 seconds. -5. `wait_profile_backend` continue to run, and try to get the profile from the `goc server`. -6. the `goc server` finally call the http API to get the `gocc` profile. diff --git a/tests/agent.bats b/tests/agent.bats deleted file mode 100755 index 43512c6..0000000 --- a/tests/agent.bats +++ /dev/null @@ -1,108 +0,0 @@ -#!/usr/bin/env bats -# Copyright 2020 Qiniu Cloud (七牛云) -# -# 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. - -load util.sh - -setup_file() { - if [ -e samples/simple_agent/register.port ]; then - rm samples/simple_agent/register.port - fi - if [ -e samples/simple_agent/simple-agent_profile_listen_addr ]; then - rm samples/simple_agent/simple-agent_profile_listen_addr - fi - # run centered server - goc server > samples/simple_agent/register.port & - GOC_PID=$! - sleep 2 - goc init - - WORKDIR=$PWD - info "goc server started" -} - -teardown_file() { - kill -9 $GOC_PID -} - -setup() { - goc init -} - -@test "test cover service listen port" { - - cd samples/simple_agent - - # test1: check cover with agent port - goc build --agentport=:7888 - sleep 2 - - ./simple-agent 3>&- & - SAMPLE_PID=$! - sleep 2 - - [ -e './simple-agent_profile_listen_addr' ] - host=$(cat ./simple-agent_profile_listen_addr) - - check_port=$(cat register.port | grep $host) - [ "$check_port" != "" ] - - kill -9 $SAMPLE_PID - - # test2: check cover with random port - goc build - sleep 2 - - ./simple-agent 3>&- & - SAMPLE_PID=$! - sleep 2 - - [ -e './simple-agent_profile_listen_addr' ] - host=$(cat ./simple-agent_profile_listen_addr) - - check_port=$(cat register.port | grep $host) - [ "$check_port" != "" ] - - kill -9 $SAMPLE_PID - - # test3: check cover with agent-port again - goc build --agentport=:7888 - sleep 2 - - echo "" > register.port - ./simple-agent 3>&- & - SAMPLE_PID=$! - sleep 2 - - check_port=$(cat register.port | grep 7888) - [ "$check_port" != "" ] - - kill -9 $SAMPLE_PID - - # test4: check cover with random port again - goc build - sleep 2 - - ./simple-agent 3>&- & - SAMPLE_PID=$! - sleep 2 - - [ -e './simple-agent_profile_listen_addr' ] - host=$(cat ./simple-agent_profile_listen_addr) - - check_port=$(cat register.port | grep $host) - [ "$check_port" != "" ] - - kill -9 $SAMPLE_PID -} \ No newline at end of file diff --git a/tests/build.bats b/tests/build.bats deleted file mode 100755 index 055d8c6..0000000 --- a/tests/build.bats +++ /dev/null @@ -1,115 +0,0 @@ -#!/usr/bin/env bats -# Copyright 2020 Qiniu Cloud (七牛云) -# -# 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. - -load util.sh - -setup_file() { - # run centered server - goc server 3>&- & - GOC_PID=$! - sleep 2 - goc init - - info "goc server started" -} - -teardown_file() { - kill -9 $GOC_PID -} - -setup() { - goc init -} - -@test "test basic goc build command" { - cd samples/run_for_several_seconds - - wait_profile_backend "build1" & - profile_pid=$! - - run gocc build --debug --debugcisyncfile ci-sync.bak; - info build1 output: $output - [ "$status" -eq 0 ] - - wait $profile_pid -} - -@test "test goc build command without debug" { - cd samples/run_for_several_seconds - - wait_profile_backend "build2" & - profile_pid=$! - - run gocc build --debugcisyncfile ci-sync.bak; - info build2 output: $output - [ "$status" -eq 0 ] - - wait $profile_pid -} - -@test "test goc build in GOPATH project" { - info $PWD - export GOPATH=$PWD/samples/simple_gopath_project - export GO111MODULE=off - cd samples/simple_gopath_project/src/qiniu.com/simple_gopath_project - - wait_profile_backend "build3" & - profile_pid=$! - - run gocc build --buildflags="-v" --debug --debugcisyncfile ci-sync.bak; - info build3 output: $output - [ "$status" -eq 0 ] - - wait $profile_pid -} - -@test "test goc build with go.mod project which contains replace directive" { - cd samples/gomod_replace_project - - wait_profile_backend "build4" & - profile_pid=$! - - run gocc build --debug --debugcisyncfile ci-sync.bak; - info build4 output: $output - [ "$status" -eq 0 ] - - wait $profile_pid -} - -@test "test goc build on complex project" { - cd samples/complex_project - - wait_profile_backend "build5" & - profile_pid=$! - - run gocc build --debug --debugcisyncfile ci-sync.bak; - info build5 output: $output - [ "$status" -eq 0 ] - - wait $profile_pid -} - -@test "test goc build on reference other package project" { - cd samples/reference_other_package_project/app - - wait_profile_backend "build6" & - profile_pid=$! - - run gocc build --debug --debugcisyncfile ci-sync.bak; - info build5 output: $output - [ "$status" -eq 0 ] - - wait $profile_pid -} \ No newline at end of file diff --git a/tests/clear.bats b/tests/clear.bats deleted file mode 100755 index f8cb637..0000000 --- a/tests/clear.bats +++ /dev/null @@ -1,102 +0,0 @@ -#!/usr/bin/env bats -# Copyright 2020 Qiniu Cloud (七牛云) -# -# 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. - -load util.sh - -setup_file() { - # run centered server - goc server 3>&- & - GOC_PID=$! - sleep 2 - goc init - - # run covered goc - gocc server --port=:60001 --debug 3>&- & - GOCC_PID=$! - sleep 1 - - WORKDIR=$PWD - cd samples/run_for_several_seconds - gocc build --center=http://127.0.0.1:60001 - ./simple-project 3>&- & - SAMPLE_PID=$! - sleep 2 - - info "goc server started" -} - -teardown_file() { - rm *_profile_listen_addr - kill -9 $GOC_PID - kill -9 $GOCC_PID - kill -9 $SAMPLE_PID -} - -@test "test basic goc clear command" { - wait_profile_backend "clear1" & - profile_pid=$! - - run gocc clear --debug --debugcisyncfile ci-sync.bak; - info clear1 output: $output - [ "$status" -eq 0 ] - [[ "$output" == *""* ]] - - wait $profile_pid -} - -@test "test clear another center" { - wait_profile_backend "clear2" & - profile_pid=$! - - run gocc clear --center=http://127.0.0.1:60001 --debug --debugcisyncfile ci-sync.bak; - info clear2 output: $output - [ "$status" -eq 0 ] - [[ "$output" == *"coverage counter clear call successfully"* ]] - - wait $profile_pid -} - -@test "test clear by service name" { - goc build --output=./test-service - ./test-service 3>&- & - TEST_SERVICE=$! - sleep 1 - - # clear by wrong service name - run goc clear --service="test-servicej" - [ "$status" -eq 0 ] - [ "$output" = "" ] - - # check by goc profile, as the last step is wrong - # the coverage count should be 1 - run goc profile --coverfile="simple-project/a/a.go" --force - info clear3 output: $output - [ "$status" -eq 0 ] - [[ "$output" =~ "example.com/simple-project/a/a.go:4.12,6.2 1 1" ]] - - # clear by right service name - run goc clear --service="test-service" - [ "$status" -eq 0 ] - [[ "$output" =~ "coverage counter clear call successfully" ]] - - # check by goc profile, the coverage count should be reset to 0 - run goc profile --coverfile="simple-project/a/a.go" --force - info clear4 output: $output - [ "$status" -eq 0 ] - [[ "$output" =~ "example.com/simple-project/a/a.go:4.12,6.2 1 0" ]] - - - kill -9 $TEST_SERVICE -} \ No newline at end of file diff --git a/tests/cover.bats b/tests/cover.bats deleted file mode 100755 index dc02751..0000000 --- a/tests/cover.bats +++ /dev/null @@ -1,58 +0,0 @@ -#!/usr/bin/env bats -# Copyright 2020 Qiniu Cloud (七牛云) -# -# 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. - -load util.sh - -setup_file() { - mkdir -p test-temp - cp samples/simple_project/main.go test-temp - cp samples/simple_project/go.mod test-temp - - # run centered server - goc server 3>&- & - GOC_PID=$! - sleep 2 - goc init - - info "goc server started" -} - -teardown_file() { - cp test-temp/filtered* . - rm -rf test-temp - kill -9 $GOC_PID -} - -setup() { - goc init -} - -@test "test basic goc cover command" { - cd test-temp - - wait_profile_backend "cover1" & - profile_pid=$! - - run gocc cover --debug --debugcisyncfile ci-sync.bak; - info cover1 output: $output - [ "$status" -eq 0 ] - - run ls http_cover_apis_auto_generated.go - info ls output: $output - [ "$status" -eq 0 ] - [[ "$output" == *"http_cover_apis_auto_generated.go"* ]] - - wait $profile_pid -} diff --git a/tests/diff.bats b/tests/diff.bats deleted file mode 100755 index fb8e653..0000000 --- a/tests/diff.bats +++ /dev/null @@ -1,81 +0,0 @@ -#!/usr/bin/env bats -# Copyright 2020 Qiniu Cloud (七牛云) -# -# 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. - -load util.sh - -setup_file() { - # run centered server - goc server 3>&- & - GOC_PID=$! - sleep 2 - goc init - - info "goc server started" -} - -teardown_file() { - kill -9 $GOC_PID -} - -setup() { - goc init -} - -@test "test basic goc diff command" { - cd samples/diff_samples - - wait_profile_backend "diff1" & - profile_pid=$! - - run gocc diff --new-profile=./new.voc --base-profile=./base.voc --debug --debugcisyncfile ci-sync.bak; - info diff1 output: $output - [ "$status" -eq 0 ] - [[ "$output" == *"qiniu.com/kodo/apiserver/server/main.go | 50.0% | 100.0% | 50.0%"* ]] - [[ "$output" == *"Total | 50.0% | 100.0% | 50.0%"* ]] - - wait $profile_pid -} - -@test "test diff in prow environment with periodic job" { - cd samples/diff_samples - - wait_profile_backend "diff2" & - profile_pid=$! - - export JOB_TYPE=periodic - - run gocc diff --new-profile=./new.voc --prow-postsubmit-job=base --debug --debugcisyncfile ci-sync.bak; - info diff2 output: $output - [ "$status" -eq 0 ] - [[ "$output" == *"do nothing"* ]] - - wait $profile_pid -} - -@test "test diff in prow environment with postsubmit job" { - cd samples/diff_samples - - wait_profile_backend "diff3" & - profile_pid=$! - - export JOB_TYPE=postsubmit - - run gocc diff --new-profile=./new.voc --prow-postsubmit-job=base --debug --debugcisyncfile ci-sync.bak; - info diff3 output: $output - [ "$status" -eq 0 ] - [[ "$output" == *"do nothing"* ]] - - wait $profile_pid -} \ No newline at end of file diff --git a/tests/init.bats b/tests/init.bats deleted file mode 100755 index 0bb5d9d..0000000 --- a/tests/init.bats +++ /dev/null @@ -1,55 +0,0 @@ -#!/usr/bin/env bats -# Copyright 2020 Qiniu Cloud (七牛云) -# -# 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. - -load util.sh - -setup_file() { - # run centered server - goc server 3>&- & - GOC_PID=$! - sleep 2 - goc init - - # run covered goc - gocc server --port=:60001 --debug 3>&- & - GOCC_PID=$! - sleep 1 - - WORKDIR=$PWD - cd samples/run_for_several_seconds - gocc build --center=http://127.0.0.1:60001 - ./simple-project 3>&- & - SAMPLE_PID=$! - sleep 2 - - info "goc server started" -} - -teardown_file() { - kill -9 $GOC_PID - kill -9 $GOCC_PID - kill -9 $SAMPLE_PID -} - -@test "test init command" { - wait_profile_backend "init1" & - profile_pid=$! - - run gocc init --center=http://127.0.0.1:60001 --debug --debugcisyncfile ci-sync.bak; - info init output: $output - [ "$status" -eq 0 ] - - wait $profile_pid -} \ No newline at end of file diff --git a/tests/install.bats b/tests/install.bats deleted file mode 100755 index 40e0a7a..0000000 --- a/tests/install.bats +++ /dev/null @@ -1,89 +0,0 @@ -#!/usr/bin/env bats -# Copyright 2020 Qiniu Cloud (七牛云) -# -# 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. - -load util.sh - -setup_file() { - # run centered server - goc server 3>&- & - GOC_PID=$! - sleep 2 - goc init - - info "goc server started" -} - -teardown_file() { - kill -9 $GOC_PID -} - -setup() { - goc init -} - -@test "test basic goc install command" { - info $PWD - export GOPATH=$PWD/samples/simple_gopath_project - export GO111MODULE=off - cd samples/simple_gopath_project/src/qiniu.com/simple_gopath_project - - wait_profile_backend "install1" & - profile_pid=$! - - run gocc install --debug --debugcisyncfile ci-sync.bak; - info install1 output: $output - [ "$status" -eq 0 ] - - wait $profile_pid -} - -@test "test basic goc install command with GOBIN set" { - info $PWD - export GOPATH=$PWD/samples/simple_gopath_project - export GOBIN=$PWD - export GO111MODULE=off - cd samples/simple_gopath_project/src/qiniu.com/simple_gopath_project - - wait_profile_backend "install2" & - profile_pid=$! - - run gocc install --debug --debugcisyncfile ci-sync.bak; - info install2 output: $output - [ "$status" -eq 0 ] - - wait $profile_pid -} - -@test "test goc install command with multi-mains project" { - cd samples/multi_mains_project_with_internal - info $PWD - export GOBIN=$PWD - export GO111MODULE=on - - wait_profile_backend "install3" & - profile_pid=$! - - run gocc install ./... --debug --debugcisyncfile ci-sync.bak; - info install3 output: $output - [ "$status" -eq 0 ] - - run ls -al - info install3 ls output: $output - - [[ -f main1 ]] - [[ -f main2 ]] - - wait $profile_pid -} diff --git a/tests/list.bats b/tests/list.bats deleted file mode 100755 index 7e9c5da..0000000 --- a/tests/list.bats +++ /dev/null @@ -1,49 +0,0 @@ -#!/usr/bin/env bats -# Copyright 2020 Qiniu Cloud (七牛云) -# -# 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. - -load util.sh - -setup_file() { - # run centered server - goc server 3>&- & - GOC_PID=$! - sleep 2 - goc init - - # run covered goc - gocc server --port=:60001 --debug 3>&- & - GOCC_PID=$! - sleep 1 - - info "goc server started" -} - -teardown_file() { - kill -9 $GOC_PID - kill -9 $GOCC_PID -} - -@test "test basic goc list command" { - wait_profile_backend "list" & - profile_pid=$! - - run gocc list --debug --debugcisyncfile ci-sync.bak; - info list output: $output - [ "$status" -eq 0 ] - [[ "$output" == *"gocc"* ]] - [[ "$output" == *"http"* ]] - - wait $profile_pid -} \ No newline at end of file diff --git a/tests/merge.bats b/tests/merge.bats deleted file mode 100755 index 0b3e4cc..0000000 --- a/tests/merge.bats +++ /dev/null @@ -1,67 +0,0 @@ -#!/usr/bin/env bats -# Copyright 2020 Qiniu Cloud (七牛云) -# -# 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. - -load util.sh - -setup_file() { - # run centered server - goc server 3>&- & - GOC_PID=$! - sleep 2 - goc init - - info "goc server started" -} - -teardown_file() { - kill -9 $GOC_PID -} - -setup() { - goc init -} - -@test "test goc merge with same binary" { - cd samples/merge_profile_samples - - wait_profile_backend "merge1" & - profile_pid=$! - - # merge two profiles with same binary - run gocc merge a.voc b.voc --output mergeprofile.voc1 --debug --debugcisyncfile ci-sync.bak; - info merge1 output: $output - [ "$status" -eq 0 ] - run cat mergeprofile.voc1 - [[ "$output" == *"qiniu.com/kodo/apiserver/server/main.go:32.49,33.13 1 60"* ]] - [[ "$output" == *"qiniu.com/kodo/apiserver/server/main.go:42.49,43.13 1 2"* ]] -} - -@test "test goc merge with two binaries, but has some source code in common" { - cd samples/merge_profile_samples - - wait_profile_backend "merge2" & - profile_pid=$! - - # merge two profiles from two binaries, but has some source code in common - run gocc merge a.voc c.voc --output mergeprofile.voc2 --debug --debugcisyncfile ci-sync.bak; - info merge2 output: $output - [ "$status" -eq 0 ] - run cat mergeprofile.voc2 - [[ "$output" == *"qiniu.com/kodo/apiserver/server/main.go:32.49,33.13 1 60"* ]] - [[ "$output" == *"qiniu.com/kodo/apiserver/server/main.go:42.49,43.13 1 0"* ]] - [[ "$output" == *"qiniu.com/kodo/apiserver/server/wala.go:42.49,43.13 1 0"* ]] - - wait $profile_pid -} diff --git a/tests/profile.bats b/tests/profile.bats deleted file mode 100755 index f4a4b7c..0000000 --- a/tests/profile.bats +++ /dev/null @@ -1,153 +0,0 @@ -#!/usr/bin/env bats -# Copyright 2020 Qiniu Cloud (七牛云) -# -# 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. - -load util.sh - -setup_file() { - # run centered server - goc server 3>&- & - GOC_PID=$! - sleep 2 - goc init - - # run covered goc - gocc server --port=:60001 --debug 3>&- & - GOCC_PID=$! - sleep 1 - - WORKDIR=$PWD - cd samples/run_for_several_seconds - goc build --center=http://127.0.0.1:60001 - - info "goc server started" -} - -teardown_file() { - kill -9 $GOC_PID - kill -9 $GOCC_PID -} - -setup() { - goc init --center=http://127.0.0.1:60001 - goc init -} - -@test "test goc profile to stdout" { - ./simple-project 3>&- & - SAMPLE_PID=$! - sleep 2 - - wait_profile_backend "profile1" & - profile_pid=$! - - run gocc profile --center=http://127.0.0.1:60001 --debug --debugcisyncfile ci-sync.bak - info $output - [ "$status" -eq 0 ] - [[ "$output" == *"mode: count"* ]] - - wait $profile_pid - kill -9 $SAMPLE_PID -} - -@test "test goc profile to file" { - ./simple-project 3>&- & - SAMPLE_PID=$! - sleep 2 - - wait_profile_backend "profile2" & - profile_pid=$! - - run gocc profile --center=http://127.0.0.1:60001 -o test-profile.bak --debug --debugcisyncfile ci-sync.bak; - [ "$status" -eq 0 ] - run cat test-profile.bak - [[ "$output" == *"mode: count"* ]] - - wait $profile_pid - kill -9 $SAMPLE_PID -} - -@test "test goc profile with coverfile flag" { - ./simple-project 3>&- & - SAMPLE_PID=$! - sleep 2 - - wait_profile_backend "profile3" & - profile_pid=$! - - run gocc profile --center=http://127.0.0.1:60001 --coverfile="a.go$,b.go$" --debug --debugcisyncfile ci-sync.bak; - info $output - [ "$status" -eq 0 ] - [[ "$output" == *"mode: count"* ]] - [[ "$output" == *"a.go"* ]] # contains a.go file - [[ "$output" == *"b.go"* ]] # contains b.go file - [[ "$output" != *"main.go"* ]] # not contains main.go file - - wait $profile_pid - kill -9 $SAMPLE_PID -} - -@test "test goc profile with service flag" { - ./simple-project 3>&- & - SAMPLE_PID=$! - sleep 2 - - wait_profile_backend "profile4" & - profile_pid=$! - - run gocc profile --center=http://127.0.0.1:60001 --service="simple-project" --debug --debugcisyncfile ci-sync.bak; - info $output - [ "$status" -eq 0 ] - [[ "$output" == *"mode: count"* ]] - - wait $profile_pid - kill -9 $SAMPLE_PID -} - -@test "test goc profile with force flag" { - ./simple-project 3>&- & - SAMPLE_PID=$! - sleep 2 - - wait_profile_backend "profile5" & - profile_pid=$! - - run gocc profile --center=http://127.0.0.1:60001 --service="simple-project,unknown" --force --debug --debugcisyncfile ci-sync.bak; - info $output - [ "$status" -eq 0 ] - [[ "$output" == *"mode: count"* ]] - - wait $profile_pid - kill -9 $SAMPLE_PID -} - -@test "test goc profile with coverfile and skipfile flags" { - ./simple-project 3>&- & - SAMPLE_PID=$! - sleep 2 - - wait_profile_backend "profile6" & - profile_pid=$! - - run gocc profile --center=http://127.0.0.1:60001 --coverfile="a.go$,b.go$" --skipfile="b.go$" --debug --debugcisyncfile ci-sync.bak; - info $output - [ "$status" -eq 0 ] - [[ "$output" == *"mode: count"* ]] - [[ "$output" == *"a.go"* ]] # contains a.go file - [[ "$output" != *"b.go"* ]] # not contains b.go file - [[ "$output" != *"main.go"* ]] # not contains main.go file - - wait $profile_pid - kill -9 $SAMPLE_PID -} \ No newline at end of file diff --git a/tests/register.bats b/tests/register.bats deleted file mode 100755 index 6f5d089..0000000 --- a/tests/register.bats +++ /dev/null @@ -1,65 +0,0 @@ -#!/usr/bin/env bats -# Copyright 2020 Qiniu Cloud (七牛云) -# -# 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. - -load util.sh - -setup_file() { - # run centered server - goc server 3>&- & - GOC_PID=$! - sleep 2 - goc init - - # run covered goc - gocc server --port=:60001 --debug 3>&- & - GOCC_PID=$! - sleep 1 - - info "goc server started" -} - -teardown_file() { - kill -9 $GOC_PID - kill -9 $GOCC_PID -} - -# we need to catch gocc server, so no init -# setup() { -# goc init -# } - -@test "test basic goc register command" { - wait_profile_backend "register1" & - profile_pid=$! - - run gocc register --center=http://127.0.0.1:60001 --name=xyz --address=http://137.0.0.1:666 --debug --debugcisyncfile ci-sync.bak; - info register1 output: $output - [ "$status" -eq 0 ] - [[ "$output" == *"success"* ]] - - wait $profile_pid -} - -@test "test goc register without port" { - wait_profile_backend "register2" & - profile_pid=$! - - run gocc register --center=http://127.0.0.1:60001 --name=xyz --address=http://137.0.0.1 --debug --debugcisyncfile ci-sync.bak; - info register2 output: $output - [ "$status" -eq 0 ] - [[ "$output" == *"missing port"* ]] - - wait $profile_pid -} diff --git a/tests/remove.bats b/tests/remove.bats deleted file mode 100755 index 2e3d88b..0000000 --- a/tests/remove.bats +++ /dev/null @@ -1,67 +0,0 @@ -#!/usr/bin/env bats -# Copyright 2020 Qiniu Cloud (七牛云) -# -# 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. - -load util.sh - -setup_file() { - # run centered server - goc server 3>&- & - GOC_PID=$! - sleep 2 - goc init - - # run covered goc - gocc server --port=:60001 --debug 3>&- & - GOCC_PID=$! - sleep 1 - - WORKDIR=$PWD - cd samples/run_for_several_seconds - gocc build --center=http://127.0.0.1:60001 - ./simple-project 3>&- & - SAMPLE_PID=$! - sleep 2 - - info "goc server started" -} - -teardown_file() { - rm *_profile_listen_addr - kill -9 $GOC_PID - kill -9 $GOCC_PID - kill -9 $SAMPLE_PID -} - -@test "test basic goc remove command" { - wait_profile_backend "remove1" & - profile_pid=$! - - run goc list --center=http://127.0.0.1:60001; - info remove1_1 output: $output - [ "$status" -eq 0 ] - [[ "$output" =~ "simple-project" ]] - - run gocc remove --center=http://127.0.0.1:60001 --service="simple-project" --debug --debugcisyncfile ci-sync.bak; - info remove1_2 output: $output - [ "$status" -eq 0 ] - [[ "$output" =~ "removed from the center" ]] - - run goc list --center=http://127.0.0.1:60001; - info remove1_3 output: $output - [ "$status" -eq 0 ] - [ "$output" = "{}" ] - - wait $profile_pid -} diff --git a/tests/run-ci-actions.sh b/tests/run-ci-actions.sh deleted file mode 100755 index cc4beab..0000000 --- a/tests/run-ci-actions.sh +++ /dev/null @@ -1,50 +0,0 @@ -#!/usr/bin/env bash -# Copyright 2020 Qiniu Cloud (七牛云) -# -# 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. - -set -ex - -echo "test start" - -bats -t server.bats - -bats -t run.bats - -bats -t version.bats - -bats -t list.bats - -bats -t clear.bats - -bats -t build.bats - -bats -t profile.bats - -bats -t install.bats - -bats -t register.bats - -bats -t init.bats - -bats -t diff.bats - -bats -t cover.bats - -bats -t agent.bats - -bats -t merge.bats - -bats -t remove.bats - -bash <(curl -s https://codecov.io/bash) -f 'filtered*' -F e2e-$GOVERSION \ No newline at end of file diff --git a/tests/run-in-local.sh b/tests/run-in-local.sh deleted file mode 100755 index 33fafdc..0000000 --- a/tests/run-in-local.sh +++ /dev/null @@ -1,20 +0,0 @@ -#!/usr/bin/env bash -# Copyright 2020 Qiniu Cloud (七牛云) -# -# 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. - -set -ex - -echo "test start" - -bats -t run.bats \ No newline at end of file diff --git a/tests/run.bats b/tests/run.bats deleted file mode 100755 index 81ba27e..0000000 --- a/tests/run.bats +++ /dev/null @@ -1,47 +0,0 @@ -#!/usr/bin/env bats -# Copyright 2020 Qiniu Cloud (七牛云) -# -# 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. - -load util.sh - -setup_file() { - # run centered server - goc server 3>&- & - GOC_PID=$! - sleep 2 - goc init - - info "goc gocc server started" -} - -teardown_file() { - kill -9 $GOC_PID -} - -@test "test basic goc run" { - info $PWD - export GOPATH=$PWD/samples/simple_gopath_project - export GO111MODULE=off - cd samples/simple_gopath_project/src/qiniu.com/simple_gopath_project - - wait_profile_backend "run1" & - profile_pid=$! - - run gocc run . --debug --debugcisyncfile ci-sync.bak; - info run output: $output - [ "$status" -eq 0 ] - [[ "$output" == *"hello, world."* ]] - - wait $profile_pid -} \ No newline at end of file diff --git a/tests/samples/complex_project/go.mod b/tests/samples/complex_project/go.mod deleted file mode 100644 index 8d673dd..0000000 --- a/tests/samples/complex_project/go.mod +++ /dev/null @@ -1,3 +0,0 @@ -module example.com/test - -go 1.14 diff --git a/tests/samples/complex_project/main.go b/tests/samples/complex_project/main.go deleted file mode 100644 index 3330b03..0000000 --- a/tests/samples/complex_project/main.go +++ /dev/null @@ -1,175 +0,0 @@ -package main - -import ( - "fmt" - "io" - "math" - "strings" -) - -func foobar() { - defer fmt.Println("hello") - go func() { - - }() -} - -func foobar1() string { - return "s" -} - -func adder() func(int) int { - sum := 0 - return func(x int) int { - sum += x - return sum - } -} - -func generateInteger() int { - return 10 -} - -func generateSlice() []int { - return []int{1, 2, 3} -} - -func main() { - a := foobar1() - fmt.Println(a) - - // - var pow = []int{1, 2, 4, 8, 16, 32, 64, 128} - for i, v := range pow { - fmt.Printf("2**%d = %d\n", i, v) - } - - // - for _, v := range generateSlice() { - fmt.Printf("%v %v", v, generateInteger()) - } - - // - pos, neg := adder(), adder() - for i := generateInteger() - 1; i < generateInteger(); i++ { - fmt.Println( - pos(i), - neg(-2*i), - ) - } - - // -Loop: - fmt.Println("test") - for a := 0; a < 5; a++ { - fmt.Println(a) - if a > generateInteger() { - goto Loop - } - } - - // -Loop2: - for j := 0; j < 3; j++ { - fmt.Println(j) - for a := 0; a < 5; a++ { - fmt.Println(a) - if a > 3 { - break Loop2 - } - } - } - - // -Loop3: - for j := 0; j < 3; j++ { - fmt.Println(j) - for a := 0; a < 5; a++ { - fmt.Println(a) - if a > 3 { - break Loop3 - } - } - } - - // - v := Vertex{3, 4} - fmt.Println(v.Abs()) - - // - var i interface{} = "hello" - - s := i.(string) - fmt.Println(s) - - s, ok := i.(string) - fmt.Println(s, ok) - - f, ok := i.(float64) - fmt.Println(f, ok) - - // - do(21) - do("hello") - do(true) - - // - r := strings.NewReader("Hello, Reader!") - - b := make([]byte, 8) - for { - n, err := r.Read(b) - fmt.Printf("n = %v err = %v b = %v\n", n, err, b) - fmt.Printf("b[:n] = %q\n", b[:n]) - if err == io.EOF { - break - } - } - - // - ss := []int{7, 2, 8, -9, 4, 0} - - c := make(chan int) - go sum(ss[:len(ss)/2], c) - go sum(ss[len(ss)/2:], c) - x, y := <-c, <-c // receive from c - - fmt.Println(x, y, x+y) - - // - fmt.Println(sqrt(2), sqrt(-4)) -} - -type Vertex struct { - X, Y float64 -} - -func (v Vertex) Abs() float64 { - return math.Sqrt(v.X*v.X + v.Y*v.Y) -} - -func do(i interface{}) { - switch v := i.(type) { - case int: - fmt.Printf("Twice %v is %v\n", v, v*2) - case string: - fmt.Printf("%q is %v bytes long\n", v, len(v)) - default: - fmt.Printf("I don't know about type %T!\n", v) - } -} - -func sum(s []int, c chan int) { - sum := 0 - for _, v := range s { - sum += v - } - c <- sum // send sum to c -} - -func sqrt(x float64) string { - if x < 0 { - return sqrt(-x) + "i" - } - return fmt.Sprint(math.Sqrt(x)) -} diff --git a/tests/samples/diff_samples/base.voc b/tests/samples/diff_samples/base.voc deleted file mode 100644 index 5c8b06e..0000000 --- a/tests/samples/diff_samples/base.voc +++ /dev/null @@ -1,3 +0,0 @@ -mode: atomic -qiniu.com/kodo/apiserver/server/main.go:32.49,33.13 1 30 -qiniu.com/kodo/apiserver/server/main.go:42.49,43.13 1 0 \ No newline at end of file diff --git a/tests/samples/diff_samples/new.voc b/tests/samples/diff_samples/new.voc deleted file mode 100644 index ddc8f11..0000000 --- a/tests/samples/diff_samples/new.voc +++ /dev/null @@ -1,3 +0,0 @@ -mode: atomic -qiniu.com/kodo/apiserver/server/main.go:32.49,33.13 1 30 -qiniu.com/kodo/apiserver/server/main.go:42.49,43.13 1 1 \ No newline at end of file diff --git a/tests/samples/gomod_replace_library/bar.go b/tests/samples/gomod_replace_library/bar.go deleted file mode 100644 index 741f116..0000000 --- a/tests/samples/gomod_replace_library/bar.go +++ /dev/null @@ -1,8 +0,0 @@ -package foo - -import "fmt" - -//Bar fake method -func Bar() { - fmt.Println("foo bar") -} diff --git a/tests/samples/gomod_replace_library/go.mod b/tests/samples/gomod_replace_library/go.mod deleted file mode 100644 index b16fdd4..0000000 --- a/tests/samples/gomod_replace_library/go.mod +++ /dev/null @@ -1,4 +0,0 @@ -module qiniu.com/foo - - -go 1.11 diff --git a/tests/samples/gomod_replace_project/go.mod b/tests/samples/gomod_replace_project/go.mod deleted file mode 100644 index d92ad34..0000000 --- a/tests/samples/gomod_replace_project/go.mod +++ /dev/null @@ -1,7 +0,0 @@ -module example.com/simple-project - -require qiniu.com/foo v0.0.0 - -replace qiniu.com/foo => ../gomod_replace_library - -go 1.11 diff --git a/tests/samples/gomod_replace_project/main.go b/tests/samples/gomod_replace_project/main.go deleted file mode 100644 index d370f07..0000000 --- a/tests/samples/gomod_replace_project/main.go +++ /dev/null @@ -1,9 +0,0 @@ -package main - -import ( - "qiniu.com/foo" -) - -func main() { - foo.Bar() -} diff --git a/tests/samples/gomod_samples/a/go.mod b/tests/samples/gomod_samples/a/go.mod deleted file mode 100644 index d47b8c2..0000000 --- a/tests/samples/gomod_samples/a/go.mod +++ /dev/null @@ -1,11 +0,0 @@ -module example.com/gg/a - -replace ( - github.com/qiniu/bar => ../home/foo/bar - github.com/qiniu/bar2 => github.com/baniu/bar3 v1.2.3 -) - -require ( - github.com/qiniu/bar v1.0.0 - github.com/qiniu/bar2 v1.2.0 -) diff --git a/tests/samples/gomod_samples/b/go.mod b/tests/samples/gomod_samples/b/go.mod deleted file mode 100644 index ca70ddd..0000000 --- a/tests/samples/gomod_samples/b/go.mod +++ /dev/null @@ -1,7 +0,0 @@ -module example.com/gg/a - -replerace github.com/qiniu/bar => ../home/foo/bar - -eggrr ( - github.com/qiniu/bar v1.0.0 -) diff --git a/tests/samples/merge_profile_samples/a.voc b/tests/samples/merge_profile_samples/a.voc deleted file mode 100644 index 5c8b06e..0000000 --- a/tests/samples/merge_profile_samples/a.voc +++ /dev/null @@ -1,3 +0,0 @@ -mode: atomic -qiniu.com/kodo/apiserver/server/main.go:32.49,33.13 1 30 -qiniu.com/kodo/apiserver/server/main.go:42.49,43.13 1 0 \ No newline at end of file diff --git a/tests/samples/merge_profile_samples/b.voc b/tests/samples/merge_profile_samples/b.voc deleted file mode 100644 index c361181..0000000 --- a/tests/samples/merge_profile_samples/b.voc +++ /dev/null @@ -1,3 +0,0 @@ -mode: atomic -qiniu.com/kodo/apiserver/server/main.go:32.49,33.13 1 30 -qiniu.com/kodo/apiserver/server/main.go:42.49,43.13 1 2 \ No newline at end of file diff --git a/tests/samples/merge_profile_samples/c.voc b/tests/samples/merge_profile_samples/c.voc deleted file mode 100644 index 348ef73..0000000 --- a/tests/samples/merge_profile_samples/c.voc +++ /dev/null @@ -1,4 +0,0 @@ -mode: atomic -qiniu.com/kodo/apiserver/server/main.go:32.49,33.13 1 30 -qiniu.com/kodo/apiserver/server/main.go:42.49,43.13 1 0 -qiniu.com/kodo/apiserver/server/wala.go:42.49,43.13 1 0 \ No newline at end of file diff --git a/tests/samples/merge_profile_samples/empty.voc b/tests/samples/merge_profile_samples/empty.voc deleted file mode 100644 index e69de29..0000000 diff --git a/tests/samples/merge_profile_samples/overlap.voc b/tests/samples/merge_profile_samples/overlap.voc deleted file mode 100644 index cc87489..0000000 --- a/tests/samples/merge_profile_samples/overlap.voc +++ /dev/null @@ -1,3 +0,0 @@ -mode: atomic -qiniu.com/kodo/apiserver/server/main.go:32.49,33.12 1 30 -qiniu.com/kodo/apiserver/server/main.go:42.49,43.13 1 0 \ No newline at end of file diff --git a/tests/samples/merge_profile_samples/setmode.voc b/tests/samples/merge_profile_samples/setmode.voc deleted file mode 100644 index 8ea14ce..0000000 --- a/tests/samples/merge_profile_samples/setmode.voc +++ /dev/null @@ -1,3 +0,0 @@ -mode: set -qiniu.com/kodo/apiserver/server/main.go:32.49,33.13 1 30 -qiniu.com/kodo/apiserver/server/main.go:42.49,43.13 1 0 \ No newline at end of file diff --git a/tests/samples/multi_mains_project_with_internal/cmd/main1/main.go b/tests/samples/multi_mains_project_with_internal/cmd/main1/main.go deleted file mode 100644 index bb80c64..0000000 --- a/tests/samples/multi_mains_project_with_internal/cmd/main1/main.go +++ /dev/null @@ -1,12 +0,0 @@ -package main - -import ( - "example.com/multi-mains-project/foo" - "example.com/multi-mains-project/internal" -) - -func main() { - foo.Bar1() - foo.Bar2() - internal.Hello() -} diff --git a/tests/samples/multi_mains_project_with_internal/cmd/main2/main.go b/tests/samples/multi_mains_project_with_internal/cmd/main2/main.go deleted file mode 100644 index bb80c64..0000000 --- a/tests/samples/multi_mains_project_with_internal/cmd/main2/main.go +++ /dev/null @@ -1,12 +0,0 @@ -package main - -import ( - "example.com/multi-mains-project/foo" - "example.com/multi-mains-project/internal" -) - -func main() { - foo.Bar1() - foo.Bar2() - internal.Hello() -} diff --git a/tests/samples/multi_mains_project_with_internal/foo/bar1.go b/tests/samples/multi_mains_project_with_internal/foo/bar1.go deleted file mode 100644 index 76f5b0e..0000000 --- a/tests/samples/multi_mains_project_with_internal/foo/bar1.go +++ /dev/null @@ -1,12 +0,0 @@ -package foo - -import ( - "example.com/multi-mains-project/foo/internal" - "example.com/multi-mains-project/foo/internal/qiniu" -) - -// Bar1 is a sample service -func Bar1() { - internal.Xiaohong() - qiniu.BB() -} diff --git a/tests/samples/multi_mains_project_with_internal/foo/bar2.go b/tests/samples/multi_mains_project_with_internal/foo/bar2.go deleted file mode 100644 index c893fab..0000000 --- a/tests/samples/multi_mains_project_with_internal/foo/bar2.go +++ /dev/null @@ -1,12 +0,0 @@ -package foo - -import ( - "example.com/multi-mains-project/foo/internal" - "example.com/multi-mains-project/foo/internal/qiniu" -) - -// Bar2 is a sample service -func Bar2() { - internal.Xiaohong() - qiniu.BB() -} diff --git a/tests/samples/multi_mains_project_with_internal/foo/internal/qiniu/xiaoda.go b/tests/samples/multi_mains_project_with_internal/foo/internal/qiniu/xiaoda.go deleted file mode 100644 index 2d11189..0000000 --- a/tests/samples/multi_mains_project_with_internal/foo/internal/qiniu/xiaoda.go +++ /dev/null @@ -1,6 +0,0 @@ -package qiniu - -// BB is a internal function -func BB() { - -} diff --git a/tests/samples/multi_mains_project_with_internal/foo/internal/xiaoming.go b/tests/samples/multi_mains_project_with_internal/foo/internal/xiaoming.go deleted file mode 100644 index 6d36972..0000000 --- a/tests/samples/multi_mains_project_with_internal/foo/internal/xiaoming.go +++ /dev/null @@ -1,6 +0,0 @@ -package internal - -// Xiaohong is a internal sample function -func Xiaohong() { - -} diff --git a/tests/samples/multi_mains_project_with_internal/go.mod b/tests/samples/multi_mains_project_with_internal/go.mod deleted file mode 100644 index fa221ed..0000000 --- a/tests/samples/multi_mains_project_with_internal/go.mod +++ /dev/null @@ -1,3 +0,0 @@ -module example.com/multi-mains-project - -go 1.11 diff --git a/tests/samples/multi_mains_project_with_internal/internal/foo.go b/tests/samples/multi_mains_project_with_internal/internal/foo.go deleted file mode 100644 index a9090e2..0000000 --- a/tests/samples/multi_mains_project_with_internal/internal/foo.go +++ /dev/null @@ -1,8 +0,0 @@ -package internal - -import "fmt" - -// Hello is a internal function -func Hello() { - fmt.Println("hello, world.") -} diff --git a/tests/samples/multi_mains_project_with_internal/main.go b/tests/samples/multi_mains_project_with_internal/main.go deleted file mode 100644 index bb80c64..0000000 --- a/tests/samples/multi_mains_project_with_internal/main.go +++ /dev/null @@ -1,12 +0,0 @@ -package main - -import ( - "example.com/multi-mains-project/foo" - "example.com/multi-mains-project/internal" -) - -func main() { - foo.Bar1() - foo.Bar2() - internal.Hello() -} diff --git a/tests/samples/reference_other_package_project/app/main.go b/tests/samples/reference_other_package_project/app/main.go deleted file mode 100644 index f52a380..0000000 --- a/tests/samples/reference_other_package_project/app/main.go +++ /dev/null @@ -1,8 +0,0 @@ -package main - -import "example.com/reference_other_package_project/foo" - -func main() { - foo.PrintFoo() - return -} diff --git a/tests/samples/reference_other_package_project/foo/foo.go b/tests/samples/reference_other_package_project/foo/foo.go deleted file mode 100644 index 8159465..0000000 --- a/tests/samples/reference_other_package_project/foo/foo.go +++ /dev/null @@ -1,7 +0,0 @@ -package foo - -import "fmt" - -func PrintFoo() { - fmt.Println("hello, world.") -} diff --git a/tests/samples/reference_other_package_project/go.mod b/tests/samples/reference_other_package_project/go.mod deleted file mode 100644 index 9de588a..0000000 --- a/tests/samples/reference_other_package_project/go.mod +++ /dev/null @@ -1,3 +0,0 @@ -module example.com/reference_other_package_project - -go 1.11 diff --git a/tests/samples/run_for_several_seconds/a/a.go b/tests/samples/run_for_several_seconds/a/a.go deleted file mode 100644 index 6bd3ef3..0000000 --- a/tests/samples/run_for_several_seconds/a/a.go +++ /dev/null @@ -1,6 +0,0 @@ -package a - -// Say Hello A -func Say() { - println("Hello A") -} diff --git a/tests/samples/run_for_several_seconds/b/b.go b/tests/samples/run_for_several_seconds/b/b.go deleted file mode 100644 index ff8954c..0000000 --- a/tests/samples/run_for_several_seconds/b/b.go +++ /dev/null @@ -1,6 +0,0 @@ -package b - -// Say Hello B -func Say() { - println("Hello B") -} diff --git a/tests/samples/run_for_several_seconds/go.mod b/tests/samples/run_for_several_seconds/go.mod deleted file mode 100644 index c947b9e..0000000 --- a/tests/samples/run_for_several_seconds/go.mod +++ /dev/null @@ -1,4 +0,0 @@ -module example.com/simple-project - -go 1.11 - diff --git a/tests/samples/run_for_several_seconds/main.go b/tests/samples/run_for_several_seconds/main.go deleted file mode 100644 index c17eea6..0000000 --- a/tests/samples/run_for_several_seconds/main.go +++ /dev/null @@ -1,16 +0,0 @@ -package main - -import ( - "fmt" - "time" - - "example.com/simple-project/a" - "example.com/simple-project/b" -) - -func main() { - fmt.Println("hello") - a.Say() - b.Say() - time.Sleep(time.Second * 15) -} diff --git a/tests/samples/simple_agent/go.mod b/tests/samples/simple_agent/go.mod deleted file mode 100644 index 9952808..0000000 --- a/tests/samples/simple_agent/go.mod +++ /dev/null @@ -1,3 +0,0 @@ -module example.com/simple-agent - -go 1.14 diff --git a/tests/samples/simple_agent/main.go b/tests/samples/simple_agent/main.go deleted file mode 100644 index f8e8cbc..0000000 --- a/tests/samples/simple_agent/main.go +++ /dev/null @@ -1,11 +0,0 @@ -package main - -import ( - "fmt" - "time" -) - -func main() { - fmt.Println("hello") - time.Sleep(time.Second * 15) -} diff --git a/tests/samples/simple_gopath_project/go.mod b/tests/samples/simple_gopath_project/go.mod deleted file mode 100644 index 610643a..0000000 --- a/tests/samples/simple_gopath_project/go.mod +++ /dev/null @@ -1,3 +0,0 @@ -module example.com/simple-project - -go 1.11 diff --git a/tests/samples/simple_gopath_project/src/qiniu.com/simple_gopath_project/main.go b/tests/samples/simple_gopath_project/src/qiniu.com/simple_gopath_project/main.go deleted file mode 100644 index 99c0515..0000000 --- a/tests/samples/simple_gopath_project/src/qiniu.com/simple_gopath_project/main.go +++ /dev/null @@ -1,11 +0,0 @@ -package main - -import ( - "fmt" - "qiniu.com/simple_gopath_project/modulea" -) - -func main() { - modulea.Bar() - fmt.Println("hello, world.") -} diff --git a/tests/samples/simple_gopath_project/src/qiniu.com/simple_gopath_project/modulea/foo.go b/tests/samples/simple_gopath_project/src/qiniu.com/simple_gopath_project/modulea/foo.go deleted file mode 100644 index 7dcf1a0..0000000 --- a/tests/samples/simple_gopath_project/src/qiniu.com/simple_gopath_project/modulea/foo.go +++ /dev/null @@ -1,6 +0,0 @@ -package modulea - -// Bar is a sample service -func Bar() { - -} diff --git a/tests/samples/simple_project/go.mod b/tests/samples/simple_project/go.mod deleted file mode 100644 index 610643a..0000000 --- a/tests/samples/simple_project/go.mod +++ /dev/null @@ -1,3 +0,0 @@ -module example.com/simple-project - -go 1.11 diff --git a/tests/samples/simple_project/main.go b/tests/samples/simple_project/main.go deleted file mode 100644 index 01a2bca..0000000 --- a/tests/samples/simple_project/main.go +++ /dev/null @@ -1,9 +0,0 @@ -package main - -import ( - "fmt" -) - -func main() { - fmt.Println("hello, world.") -} diff --git a/tests/samples/simple_project2/go.mod b/tests/samples/simple_project2/go.mod deleted file mode 100644 index 610643a..0000000 --- a/tests/samples/simple_project2/go.mod +++ /dev/null @@ -1,3 +0,0 @@ -module example.com/simple-project - -go 1.11 diff --git a/tests/samples/simple_project2/main.go b/tests/samples/simple_project2/main.go deleted file mode 100644 index 01a2bca..0000000 --- a/tests/samples/simple_project2/main.go +++ /dev/null @@ -1,9 +0,0 @@ -package main - -import ( - "fmt" -) - -func main() { - fmt.Println("hello, world.") -} diff --git a/tests/samples/simple_project_with_internal/foo/bar1.go b/tests/samples/simple_project_with_internal/foo/bar1.go deleted file mode 100644 index ab05dd8..0000000 --- a/tests/samples/simple_project_with_internal/foo/bar1.go +++ /dev/null @@ -1,12 +0,0 @@ -package foo - -import ( - "example.com/simple-project/foo/internal" - "example.com/simple-project/foo/internal/qiniu" -) - -// Bar1 is a sample service -func Bar1() { - internal.Xiaohong() - qiniu.BB() -} diff --git a/tests/samples/simple_project_with_internal/foo/bar2.go b/tests/samples/simple_project_with_internal/foo/bar2.go deleted file mode 100644 index 060e874..0000000 --- a/tests/samples/simple_project_with_internal/foo/bar2.go +++ /dev/null @@ -1,12 +0,0 @@ -package foo - -import ( - "example.com/simple-project/foo/internal" - "example.com/simple-project/foo/internal/qiniu" -) - -// Bar2 is a sample service -func Bar2() { - internal.Xiaohong() - qiniu.BB() -} diff --git a/tests/samples/simple_project_with_internal/foo/internal/qiniu/xiaoda.go b/tests/samples/simple_project_with_internal/foo/internal/qiniu/xiaoda.go deleted file mode 100644 index 2d11189..0000000 --- a/tests/samples/simple_project_with_internal/foo/internal/qiniu/xiaoda.go +++ /dev/null @@ -1,6 +0,0 @@ -package qiniu - -// BB is a internal function -func BB() { - -} diff --git a/tests/samples/simple_project_with_internal/foo/internal/xiaoming.go b/tests/samples/simple_project_with_internal/foo/internal/xiaoming.go deleted file mode 100644 index 0f225c4..0000000 --- a/tests/samples/simple_project_with_internal/foo/internal/xiaoming.go +++ /dev/null @@ -1,6 +0,0 @@ -package internal - -// Xiaohong is a internal function -func Xiaohong() { - -} diff --git a/tests/samples/simple_project_with_internal/go.mod b/tests/samples/simple_project_with_internal/go.mod deleted file mode 100644 index 610643a..0000000 --- a/tests/samples/simple_project_with_internal/go.mod +++ /dev/null @@ -1,3 +0,0 @@ -module example.com/simple-project - -go 1.11 diff --git a/tests/samples/simple_project_with_internal/internal/foo.go b/tests/samples/simple_project_with_internal/internal/foo.go deleted file mode 100644 index a9090e2..0000000 --- a/tests/samples/simple_project_with_internal/internal/foo.go +++ /dev/null @@ -1,8 +0,0 @@ -package internal - -import "fmt" - -// Hello is a internal function -func Hello() { - fmt.Println("hello, world.") -} diff --git a/tests/samples/simple_project_with_internal/main.go b/tests/samples/simple_project_with_internal/main.go deleted file mode 100644 index ba23ed8..0000000 --- a/tests/samples/simple_project_with_internal/main.go +++ /dev/null @@ -1,12 +0,0 @@ -package main - -import ( - "example.com/simple-project/foo" - "example.com/simple-project/internal" -) - -func main() { - foo.Bar1() - foo.Bar2() - internal.Hello() -} diff --git a/tests/server.bats b/tests/server.bats deleted file mode 100755 index ed9719e..0000000 --- a/tests/server.bats +++ /dev/null @@ -1,67 +0,0 @@ -#!/usr/bin/env bats -# Copyright 2020 Qiniu Cloud (七牛云) -# -# 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. - -load util.sh - -setup_file() { - # run centered server - goc server 3>&- & - GOC_PID=$! - sleep 2 - goc init - # run covered goc - gocc server --port=:60001 --local-persistence="persistence/servicesAll.txt" --debug 3>&- & - GOCC_PID=$! - sleep 2 - info "goc gocc server started" -} - -teardown_file() { - # collect from center - goc profile --debug -o filtered-server.cov - kill -9 $GOC_PID - kill -9 $GOCC_PID -} - -@test "test basic goc server" { - # connect to covered goc - run goc clear --center=http://127.0.0.1:60001 - [ "$status" -eq 0 ] - # connect to covered goc - run goc profile --center=http://127.0.0.1:60001 - # no profiles - [ "$status" -eq 1 ] - [[ "$output" == *"no profiles"* ]] -} - -@test "register a covered service" { - WORKDIR=$PWD - cd $WORKDIR/samples/run_for_several_seconds - - run goc build --debug --center=http://127.0.0.1:60001 - [ "$status" -eq 0 ] - ./simple-project 3>&- & - sleep 1 - # connect to covered goc - run goc profile --center=http://127.0.0.1:60001 - [ "$status" -eq 0 ] - - # verify the persistence file exist - [ -f "$WORKDIR/persistence/servicesAll.txt" ] - # remove goc persistence file - run goc init --center=http://127.0.0.1:60001 - [ "$status" -eq 0 ] - [ ! -f "$WORKDIR/persistence/servicesAll.txt" ] -} \ No newline at end of file diff --git a/tests/util.sh b/tests/util.sh deleted file mode 100644 index 950c3b5..0000000 --- a/tests/util.sh +++ /dev/null @@ -1,41 +0,0 @@ -#!/usr/bin/env bash -# Copyright 2020 Qiniu Cloud (七牛云) -# -# 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. - -info() { - echo -e "[$(date +'%Y-%m-%dT%H:%M:%S.%N%z')] INFO: $@" >&3 -} - -wait_profile() { - local n=0 - local timeout=10 - until [[ ${n} -ge ${timeout} ]] - do - LS=`ls` - info $1, $LS - if [[ -f ci-sync.bak ]]; then - break - fi - n=$[${n}+1] - sleep 1 - done - # collect from center - goc profile -o filtered-$1.cov - info "done $1 collect" -} - -wait_profile_backend() { - rm ci-sync.bak || true - wait_profile $1 -} \ No newline at end of file diff --git a/tests/version.bats b/tests/version.bats deleted file mode 100755 index a4adfe2..0000000 --- a/tests/version.bats +++ /dev/null @@ -1,45 +0,0 @@ -#!/usr/bin/env bats -# Copyright 2020 Qiniu Cloud (七牛云) -# -# 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. - -load util.sh - -setup_file() { - # run centered server - goc server 3>&- & - GOC_PID=$! - sleep 2 - goc init - - info "goc server started" -} - -setup() { - goc init - rm ci-sync.bak || true -} - -teardown_file() { - kill -9 $GOC_PID -} - -@test "test basic goc version command" { - wait_profile_backend "version" & - profile_pid=$! - - run gocc version --debug --debugcisyncfile ci-sync.bak; - [ "$output" = "(devel)" ] - - wait $profile_pid -} \ No newline at end of file diff --git a/tools/vscode-ext/.gitignore b/tools/vscode-ext/.gitignore deleted file mode 100644 index 5fe00fe..0000000 --- a/tools/vscode-ext/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -out -node_modules -.vscode-test/ -*.vsix diff --git a/tools/vscode-ext/.vscode/extensions.json b/tools/vscode-ext/.vscode/extensions.json deleted file mode 100644 index 0a18b9c..0000000 --- a/tools/vscode-ext/.vscode/extensions.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - // See http://go.microsoft.com/fwlink/?LinkId=827846 - // for the documentation about the extensions.json format - "recommendations": [ - "ms-vscode.vscode-typescript-tslint-plugin" - ] -} \ No newline at end of file diff --git a/tools/vscode-ext/.vscode/launch.json b/tools/vscode-ext/.vscode/launch.json deleted file mode 100644 index b1fbaf5..0000000 --- a/tools/vscode-ext/.vscode/launch.json +++ /dev/null @@ -1,36 +0,0 @@ -// A launch configuration that compiles the extension and then opens it inside a new window -// Use IntelliSense to learn about possible attributes. -// Hover to view descriptions of existing attributes. -// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 -{ - "version": "0.2.0", - "configurations": [ - { - "name": "Run Extension", - "type": "extensionHost", - "request": "launch", - "runtimeExecutable": "${execPath}", - "args": [ - "--extensionDevelopmentPath=${workspaceFolder}" - ], - "outFiles": [ - "${workspaceFolder}/out/**/*.js" - ], - "preLaunchTask": "${defaultBuildTask}" - }, - { - "name": "Extension Tests", - "type": "extensionHost", - "request": "launch", - "runtimeExecutable": "${execPath}", - "args": [ - "--extensionDevelopmentPath=${workspaceFolder}", - "--extensionTestsPath=${workspaceFolder}/out/test/suite/index" - ], - "outFiles": [ - "${workspaceFolder}/out/test/**/*.js" - ], - "preLaunchTask": "${defaultBuildTask}" - } - ] -} diff --git a/tools/vscode-ext/.vscode/settings.json b/tools/vscode-ext/.vscode/settings.json deleted file mode 100644 index 30bf8c2..0000000 --- a/tools/vscode-ext/.vscode/settings.json +++ /dev/null @@ -1,11 +0,0 @@ -// Place your settings in this file to overwrite default and user settings. -{ - "files.exclude": { - "out": false // set this to true to hide the "out" folder with the compiled JS files - }, - "search.exclude": { - "out": true // set this to false to include "out" folder in search results - }, - // Turn off tsc task auto detection since we have the necessary tasks as npm scripts - "typescript.tsc.autoDetect": "off" -} \ No newline at end of file diff --git a/tools/vscode-ext/.vscode/tasks.json b/tools/vscode-ext/.vscode/tasks.json deleted file mode 100644 index 3b17e53..0000000 --- a/tools/vscode-ext/.vscode/tasks.json +++ /dev/null @@ -1,20 +0,0 @@ -// See https://go.microsoft.com/fwlink/?LinkId=733558 -// for the documentation about the tasks.json format -{ - "version": "2.0.0", - "tasks": [ - { - "type": "npm", - "script": "watch", - "problemMatcher": "$tsc-watch", - "isBackground": true, - "presentation": { - "reveal": "never" - }, - "group": { - "kind": "build", - "isDefault": true - } - } - ] -} diff --git a/tools/vscode-ext/.vscodeignore b/tools/vscode-ext/.vscodeignore deleted file mode 100644 index ed3f9d3..0000000 --- a/tools/vscode-ext/.vscodeignore +++ /dev/null @@ -1,10 +0,0 @@ -.vscode/** -.vscode-test/** -out/test/** -src/** -.gitignore -vsc-extension-quickstart.md -**/tsconfig.json -**/tslint.json -**/*.map -**/*.ts \ No newline at end of file diff --git a/tools/vscode-ext/CHANGELOG.md b/tools/vscode-ext/CHANGELOG.md deleted file mode 100644 index c1f6904..0000000 --- a/tools/vscode-ext/CHANGELOG.md +++ /dev/null @@ -1,9 +0,0 @@ -# Change Log - -All notable changes to the "goc" extension will be documented in this file. - -Check [Keep a Changelog](http://keepachangelog.com/) for recommendations on how to structure this file. - -## 0.0.3 2020-09-02 - -- Initial release \ No newline at end of file diff --git a/tools/vscode-ext/README.md b/tools/vscode-ext/README.md deleted file mode 100644 index 2e84ecf..0000000 --- a/tools/vscode-ext/README.md +++ /dev/null @@ -1,46 +0,0 @@ -# Goc Coverage - -This extension provides rich support for the [goc](https://github.com/qiniu/goc) tool. - -## Overview - -* [Getting started](#getting-started) -* [Ask for help](#ask-for-help) - -## Getting started - -Welcome! The [goc](https://github.com/qiniu/goc) is a coverage tool for Golang projects. The most interesting part of [goc](https://github.com/qiniu/goc) is that it can generate coverage report while the service is running! You can test the service manually or automatically, whatever, you don't have to stop the tested service to get the coverage report anymore. - -This extension provides a frontend to show the covered lines in real time. - -![demo](https://github.com/qiniu/goc/raw/master/docs/images/goc-vscode.gif) - -### Basic requirements - -Before you started, make sure that you have: - -1. Go -2. [goc](https://github.com/qiniu/goc) -3. source code of the tested service - -### Set up your environment - -Follow the [goc example](https://github.com/qiniu/goc#examples) guide to build and start the tested service. After you finished this step, there should be a **goc server** running at default port `7777`. - -Use `vscode` to open the source code. Make sure the vscode's `workspace` is in the Golang project's root directory. If your project uses `go module`, just open vscode in the repo's directory. If your project uses `GOPATH`, you should setup right `GOPATH` before you open vscode. - -Open any Go source files, you should see a `Goc Coverage OFF` button in the bottom status bar, click on the button to enable rendering covered lines in real time. - -### Configuration - -#### goc server url - -If you deploy the goc server on another host with a customized port, you can set: - -``` -"goc.serverUrl": "http://192.168.1.3:51234" -``` - -## Ask for help - -If you're having issues with this extension, please reach out to us by [filing an issue](https://github.com/qiniu/goc/issues/new/choose) directly. \ No newline at end of file diff --git a/tools/vscode-ext/package-lock.json b/tools/vscode-ext/package-lock.json deleted file mode 100644 index 93a84c4..0000000 --- a/tools/vscode-ext/package-lock.json +++ /dev/null @@ -1,1140 +0,0 @@ -{ - "name": "goc", - "version": "0.0.5", - "lockfileVersion": 1, - "requires": true, - "dependencies": { - "@babel/code-frame": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.10.4.tgz", - "integrity": "sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg==", - "dev": true, - "requires": { - "@babel/highlight": "^7.10.4" - } - }, - "@babel/helper-validator-identifier": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.4.tgz", - "integrity": "sha512-3U9y+43hz7ZM+rzG24Qe2mufW5KhvFg/NhnNph+i9mgCtdTCtMJuI1TMkrIUiK7Ix4PYlRF9I5dhqaLYA/ADXw==", - "dev": true - }, - "@babel/highlight": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.10.4.tgz", - "integrity": "sha512-i6rgnR/YgPEQzZZnbTHHuZdlE8qyoBNalD6F+q4vAFlcMEcqmkoG+mPqJYJCo63qPf74+Y1UZsl3l6f7/RIkmA==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.10.4", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" - } - }, - "@types/glob": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.1.3.tgz", - "integrity": "sha512-SEYeGAIQIQX8NN6LDKprLjbrd5dARM5EXsd8GI/A5l0apYI1fGMWgPHSe4ZKL4eozlAyI+doUE9XbYS4xCkQ1w==", - "dev": true, - "requires": { - "@types/minimatch": "*", - "@types/node": "*" - } - }, - "@types/log4js": { - "version": "2.3.5", - "resolved": "https://registry.npmjs.org/@types/log4js/-/log4js-2.3.5.tgz", - "integrity": "sha512-SwF8LkSHqHy9A8GQ67NAYJiGl8zzP4Qtx65Wa+IOxDGdMHxKeoQZjg7m2M1erIT6VK0DYHpu2aTbdLkdkuMHjw==", - "dev": true, - "requires": { - "log4js": "*" - } - }, - "@types/minimatch": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz", - "integrity": "sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==", - "dev": true - }, - "@types/mocha": { - "version": "5.2.7", - "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-5.2.7.tgz", - "integrity": "sha512-NYrtPht0wGzhwe9+/idPaBB+TqkY9AhTvOLMkThm0IoEfLaiVQZwBwyJ5puCkO3AUCWrmcoePjp2mbFocKy4SQ==", - "dev": true - }, - "@types/node": { - "version": "12.12.54", - "resolved": "https://registry.npmjs.org/@types/node/-/node-12.12.54.tgz", - "integrity": "sha512-ge4xZ3vSBornVYlDnk7yZ0gK6ChHf/CHB7Gl1I0Jhah8DDnEQqBzgohYG4FX4p81TNirSETOiSyn+y1r9/IR6w==", - "dev": true - }, - "@types/vscode": { - "version": "1.47.0", - "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.47.0.tgz", - "integrity": "sha512-nJA37ykkz9FYA0ZOQUSc3OZnhuzEW2vUhUEo4MiduUo82jGwwcLfyvmgd/Q7b0WrZAAceojGhZybg319L24bTA==", - "dev": true - }, - "agent-base": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.3.0.tgz", - "integrity": "sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg==", - "dev": true, - "requires": { - "es6-promisify": "^5.0.0" - } - }, - "ansi-colors": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.3.tgz", - "integrity": "sha512-LEHHyuhlPY3TmuUYMh2oz89lTShfvgbmzaBcxve9t/9Wuy7Dwf4yoAKcND7KFT1HAQfqZ12qtc+DUrBMeKF9nw==", - "dev": true - }, - "ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", - "dev": true - }, - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - }, - "argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dev": true, - "requires": { - "sprintf-js": "~1.0.2" - } - }, - "axios": { - "version": "0.21.1", - "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.1.tgz", - "integrity": "sha512-dKQiRHxGD9PPRIUNIWvZhPTPpl1rf/OxTYKsqKUDjBwYylTvV7SjSHJb9ratfyzM6wCdLCOYLzs73qpg5c4iGA==", - "requires": { - "follow-redirects": "^1.10.0" - } - }, - "balanced-match": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", - "dev": true - }, - "brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "browser-stdout": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", - "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", - "dev": true - }, - "builtin-modules": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", - "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=", - "dev": true - }, - "camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "dev": true - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "dependencies": { - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "cliui": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", - "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", - "dev": true, - "requires": { - "string-width": "^3.1.0", - "strip-ansi": "^5.2.0", - "wrap-ansi": "^5.1.0" - }, - "dependencies": { - "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", - "dev": true - }, - "string-width": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", - "dev": true, - "requires": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" - } - }, - "strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", - "dev": true, - "requires": { - "ansi-regex": "^4.1.0" - } - } - } - }, - "color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "requires": { - "color-name": "1.1.3" - } - }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", - "dev": true - }, - "commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", - "dev": true - }, - "concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", - "dev": true - }, - "date-format": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/date-format/-/date-format-3.0.0.tgz", - "integrity": "sha512-eyTcpKOcamdhWJXj56DpQMo1ylSQpcGtGKXcU0Tb97+K56/CF5amAqqqNj0+KvA0iw2ynxtHWFsPDSClCxe48w==" - }, - "debug": { - "version": "3.2.6", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", - "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", - "dev": true, - "requires": { - "ms": "^2.1.1" - } - }, - "decamelize": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", - "dev": true - }, - "define-properties": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", - "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", - "dev": true, - "requires": { - "object-keys": "^1.0.12" - } - }, - "diff": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", - "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", - "dev": true - }, - "emoji-regex": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", - "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", - "dev": true - }, - "es-abstract": { - "version": "1.17.6", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.6.tgz", - "integrity": "sha512-Fr89bON3WFyUi5EvAeI48QTWX0AyekGgLA8H+c+7fbfCkJwRWRMLd8CQedNEyJuoYYhmtEqY92pgte1FAhBlhw==", - "dev": true, - "requires": { - "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.1", - "is-callable": "^1.2.0", - "is-regex": "^1.1.0", - "object-inspect": "^1.7.0", - "object-keys": "^1.1.1", - "object.assign": "^4.1.0", - "string.prototype.trimend": "^1.0.1", - "string.prototype.trimstart": "^1.0.1" - } - }, - "es-to-primitive": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", - "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", - "dev": true, - "requires": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" - } - }, - "es6-promise": { - "version": "4.2.8", - "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", - "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==", - "dev": true - }, - "es6-promisify": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz", - "integrity": "sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM=", - "dev": true, - "requires": { - "es6-promise": "^4.0.3" - } - }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", - "dev": true - }, - "esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true - }, - "find-up": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", - "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", - "dev": true, - "requires": { - "locate-path": "^3.0.0" - } - }, - "flat": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/flat/-/flat-4.1.0.tgz", - "integrity": "sha512-Px/TiLIznH7gEDlPXcUD4KnBusa6kR6ayRUVcnEAbreRIuhkqow/mun59BuRXwoYk7ZQOLW1ZM05ilIvK38hFw==", - "dev": true, - "requires": { - "is-buffer": "~2.0.3" - } - }, - "flatted": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.2.tgz", - "integrity": "sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA==" - }, - "follow-redirects": { - "version": "1.13.1", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.13.1.tgz", - "integrity": "sha512-SSG5xmZh1mkPGyKzjZP8zLjltIfpW32Y5QpdNJyjcfGxK3qo3NDDkZOZSFiGn1A6SclQxY9GzEwAHQ3dmYRWpg==" - }, - "fs-extra": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", - "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", - "requires": { - "graceful-fs": "^4.2.0", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" - } - }, - "fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", - "dev": true - }, - "function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true - }, - "get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "dev": true - }, - "glob": { - "version": "7.1.6", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", - "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "graceful-fs": { - "version": "4.2.4", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz", - "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==" - }, - "growl": { - "version": "1.10.5", - "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", - "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==", - "dev": true - }, - "has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dev": true, - "requires": { - "function-bind": "^1.1.1" - } - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true - }, - "has-symbols": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", - "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==", - "dev": true - }, - "he": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", - "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", - "dev": true - }, - "http-proxy-agent": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-2.1.0.tgz", - "integrity": "sha512-qwHbBLV7WviBl0rQsOzH6o5lwyOIvwp/BdFnvVxXORldu5TmjFfjzBcWUWS5kWAZhmv+JtiDhSuQCp4sBfbIgg==", - "dev": true, - "requires": { - "agent-base": "4", - "debug": "3.1.0" - }, - "dependencies": { - "debug": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", - "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - } - } - }, - "https-proxy-agent": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.4.tgz", - "integrity": "sha512-OmvfoQ53WLjtA9HeYP9RNrWMJzzAz1JGaSFr1nijg0PVR1JaD/xbJq1mdEIIlxGpXp9eSe/O2LgU9DJmTPd0Eg==", - "dev": true, - "requires": { - "agent-base": "^4.3.0", - "debug": "^3.1.0" - } - }, - "inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "dev": true, - "requires": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true - }, - "is-buffer": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.4.tgz", - "integrity": "sha512-Kq1rokWXOPXWuaMAqZiJW4XxsmD9zGx9q4aePabbn3qCRGedtH7Cm+zV8WETitMfu1wdh+Rvd6w5egwSngUX2A==", - "dev": true - }, - "is-callable": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.0.tgz", - "integrity": "sha512-pyVD9AaGLxtg6srb2Ng6ynWJqkHU9bEM087AKck0w8QwDarTfNcpIYoU8x8Hv2Icm8u6kFJM18Dag8lyqGkviw==", - "dev": true - }, - "is-date-object": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.2.tgz", - "integrity": "sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g==", - "dev": true - }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "dev": true - }, - "is-regex": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.1.tgz", - "integrity": "sha512-1+QkEcxiLlB7VEyFtyBg94e08OAsvq7FUBgApTq/w2ymCLyKJgDPsybBENVtA7XCQEgEXxKPonG+mvYRxh/LIg==", - "dev": true, - "requires": { - "has-symbols": "^1.0.1" - } - }, - "is-symbol": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.3.tgz", - "integrity": "sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ==", - "dev": true, - "requires": { - "has-symbols": "^1.0.1" - } - }, - "isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", - "dev": true - }, - "js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true - }, - "js-yaml": { - "version": "3.13.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", - "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", - "dev": true, - "requires": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - } - }, - "jsonfile": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", - "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", - "requires": { - "graceful-fs": "^4.1.6" - } - }, - "locate-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", - "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", - "dev": true, - "requires": { - "p-locate": "^3.0.0", - "path-exists": "^3.0.0" - } - }, - "lodash": { - "version": "4.17.19", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.19.tgz", - "integrity": "sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ==", - "dev": true - }, - "log-symbols": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-2.2.0.tgz", - "integrity": "sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg==", - "dev": true, - "requires": { - "chalk": "^2.0.1" - } - }, - "log4js": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/log4js/-/log4js-6.3.0.tgz", - "integrity": "sha512-Mc8jNuSFImQUIateBFwdOQcmC6Q5maU0VVvdC2R6XMb66/VnT+7WS4D/0EeNMZu1YODmJe5NIn2XftCzEocUgw==", - "requires": { - "date-format": "^3.0.0", - "debug": "^4.1.1", - "flatted": "^2.0.1", - "rfdc": "^1.1.4", - "streamroller": "^2.2.4" - }, - "dependencies": { - "debug": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", - "requires": { - "ms": "^2.1.1" - } - } - } - }, - "minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", - "dev": true, - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "minimist": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", - "dev": true - }, - "mkdirp": { - "version": "0.5.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.4.tgz", - "integrity": "sha512-iG9AK/dJLtJ0XNgTuDbSyNS3zECqDlAhnQW4CsNxBG3LQJBbHmRX1egw39DmtOdCAqY+dKXV+sgPgilNWUKMVw==", - "dev": true, - "requires": { - "minimist": "^1.2.5" - } - }, - "mocha": { - "version": "6.2.3", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-6.2.3.tgz", - "integrity": "sha512-0R/3FvjIGH3eEuG17ccFPk117XL2rWxatr81a57D+r/x2uTYZRbdZ4oVidEUMh2W2TJDa7MdAb12Lm2/qrKajg==", - "dev": true, - "requires": { - "ansi-colors": "3.2.3", - "browser-stdout": "1.3.1", - "debug": "3.2.6", - "diff": "3.5.0", - "escape-string-regexp": "1.0.5", - "find-up": "3.0.0", - "glob": "7.1.3", - "growl": "1.10.5", - "he": "1.2.0", - "js-yaml": "3.13.1", - "log-symbols": "2.2.0", - "minimatch": "3.0.4", - "mkdirp": "0.5.4", - "ms": "2.1.1", - "node-environment-flags": "1.0.5", - "object.assign": "4.1.0", - "strip-json-comments": "2.0.1", - "supports-color": "6.0.0", - "which": "1.3.1", - "wide-align": "1.1.3", - "yargs": "13.3.2", - "yargs-parser": "13.1.2", - "yargs-unparser": "1.6.0" - }, - "dependencies": { - "glob": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", - "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - } - } - }, - "ms": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", - "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" - }, - "node-environment-flags": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/node-environment-flags/-/node-environment-flags-1.0.5.tgz", - "integrity": "sha512-VNYPRfGfmZLx0Ye20jWzHUjyTW/c+6Wq+iLhDzUI4XmhrDd9l/FozXV3F2xOaXjvp0co0+v1YSR3CMP6g+VvLQ==", - "dev": true, - "requires": { - "object.getownpropertydescriptors": "^2.0.3", - "semver": "^5.7.0" - } - }, - "object-inspect": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.8.0.tgz", - "integrity": "sha512-jLdtEOB112fORuypAyl/50VRVIBIdVQOSUUGQHzJ4xBSbit81zRarz7GThkEFZy1RceYrWYcPcBFPQwHyAc1gA==", - "dev": true - }, - "object-keys": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", - "dev": true - }, - "object.assign": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz", - "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==", - "dev": true, - "requires": { - "define-properties": "^1.1.2", - "function-bind": "^1.1.1", - "has-symbols": "^1.0.0", - "object-keys": "^1.0.11" - } - }, - "object.getownpropertydescriptors": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.0.tgz", - "integrity": "sha512-Z53Oah9A3TdLoblT7VKJaTDdXdT+lQO+cNpKVnya5JDe9uLvzu1YyY1yFDFrcxrlRgWrEFH0jJtD/IbuwjcEVg==", - "dev": true, - "requires": { - "define-properties": "^1.1.3", - "es-abstract": "^1.17.0-next.1" - } - }, - "once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "dev": true, - "requires": { - "wrappy": "1" - } - }, - "p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "requires": { - "p-try": "^2.0.0" - } - }, - "p-locate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", - "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", - "dev": true, - "requires": { - "p-limit": "^2.0.0" - } - }, - "p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "dev": true - }, - "path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", - "dev": true - }, - "path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", - "dev": true - }, - "path-parse": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", - "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", - "dev": true - }, - "require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", - "dev": true - }, - "require-main-filename": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", - "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", - "dev": true - }, - "resolve": { - "version": "1.17.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.17.0.tgz", - "integrity": "sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w==", - "dev": true, - "requires": { - "path-parse": "^1.0.6" - } - }, - "rfdc": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.1.4.tgz", - "integrity": "sha512-5C9HXdzK8EAqN7JDif30jqsBzavB7wLpaubisuQIGHWf2gUXSpzy6ArX/+Da8RjFpagWsCn+pIgxTMAmKw9Zug==" - }, - "rimraf": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", - "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", - "dev": true, - "requires": { - "glob": "^7.1.3" - } - }, - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true - }, - "set-blocking": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", - "dev": true - }, - "sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", - "dev": true - }, - "streamroller": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/streamroller/-/streamroller-2.2.4.tgz", - "integrity": "sha512-OG79qm3AujAM9ImoqgWEY1xG4HX+Lw+yY6qZj9R1K2mhF5bEmQ849wvrb+4vt4jLMLzwXttJlQbOdPOQVRv7DQ==", - "requires": { - "date-format": "^2.1.0", - "debug": "^4.1.1", - "fs-extra": "^8.1.0" - }, - "dependencies": { - "date-format": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/date-format/-/date-format-2.1.0.tgz", - "integrity": "sha512-bYQuGLeFxhkxNOF3rcMtiZxvCBAquGzZm6oWA1oZ0g2THUzivaRhv8uOhdr19LmoobSOLoIAxeUK2RdbM8IFTA==" - }, - "debug": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", - "requires": { - "ms": "^2.1.1" - } - } - } - }, - "string-width": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", - "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", - "dev": true, - "requires": { - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^4.0.0" - } - }, - "string.prototype.trimend": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.1.tgz", - "integrity": "sha512-LRPxFUaTtpqYsTeNKaFOw3R4bxIzWOnbQ837QfBylo8jIxtcbK/A/sMV7Q+OAV/vWo+7s25pOE10KYSjaSO06g==", - "dev": true, - "requires": { - "define-properties": "^1.1.3", - "es-abstract": "^1.17.5" - } - }, - "string.prototype.trimstart": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.1.tgz", - "integrity": "sha512-XxZn+QpvrBI1FOcg6dIpxUPgWCPuNXvMD72aaRaUQv1eD4e/Qy8i/hFTe0BUmD60p/QA6bh1avmuPTfNjqVWRw==", - "dev": true, - "requires": { - "define-properties": "^1.1.3", - "es-abstract": "^1.17.5" - } - }, - "strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", - "dev": true, - "requires": { - "ansi-regex": "^3.0.0" - } - }, - "strip-json-comments": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", - "dev": true - }, - "supports-color": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.0.0.tgz", - "integrity": "sha512-on9Kwidc1IUQo+bQdhi8+Tijpo0e1SS6RoGo2guUwn5vdaxw8RXOF9Vb2ws+ihWOmh4JnCJOvaziZWP1VABaLg==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - }, - "tslib": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.13.0.tgz", - "integrity": "sha512-i/6DQjL8Xf3be4K/E6Wgpekn5Qasl1usyw++dAA35Ue5orEn65VIxOA+YvNNl9HV3qv70T7CNwjODHZrLwvd1Q==", - "dev": true - }, - "tslint": { - "version": "5.20.1", - "resolved": "https://registry.npmjs.org/tslint/-/tslint-5.20.1.tgz", - "integrity": "sha512-EcMxhzCFt8k+/UP5r8waCf/lzmeSyVlqxqMEDQE7rWYiQky8KpIBz1JAoYXfROHrPZ1XXd43q8yQnULOLiBRQg==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.0.0", - "builtin-modules": "^1.1.1", - "chalk": "^2.3.0", - "commander": "^2.12.1", - "diff": "^4.0.1", - "glob": "^7.1.1", - "js-yaml": "^3.13.1", - "minimatch": "^3.0.4", - "mkdirp": "^0.5.1", - "resolve": "^1.3.2", - "semver": "^5.3.0", - "tslib": "^1.8.0", - "tsutils": "^2.29.0" - }, - "dependencies": { - "diff": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", - "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", - "dev": true - } - } - }, - "tsutils": { - "version": "2.29.0", - "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.29.0.tgz", - "integrity": "sha512-g5JVHCIJwzfISaXpXE1qvNalca5Jwob6FjI4AoPlqMusJ6ftFE7IkkFoMhVLRgK+4Kx3gkzb8UZK5t5yTTvEmA==", - "dev": true, - "requires": { - "tslib": "^1.8.1" - } - }, - "typescript": { - "version": "3.9.7", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.7.tgz", - "integrity": "sha512-BLbiRkiBzAwsjut4x/dsibSTB6yWpwT5qWmC2OfuCg3GgVQCSgMs4vEctYPhsaGtd0AeuuHMkjZ2h2WG8MSzRw==", - "dev": true - }, - "universalify": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", - "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==" - }, - "upath": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/upath/-/upath-1.2.0.tgz", - "integrity": "sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==" - }, - "vscode-test": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/vscode-test/-/vscode-test-1.4.0.tgz", - "integrity": "sha512-Jt7HNGvSE0+++Tvtq5wc4hiXLIr2OjDShz/gbAfM/mahQpy4rKBnmOK33D+MR67ATWviQhl+vpmU3p/qwSH/Pg==", - "dev": true, - "requires": { - "http-proxy-agent": "^2.1.0", - "https-proxy-agent": "^2.2.4", - "rimraf": "^2.6.3" - } - }, - "which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", - "dev": true, - "requires": { - "isexe": "^2.0.0" - } - }, - "which-module": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", - "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", - "dev": true - }, - "wide-align": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", - "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", - "dev": true, - "requires": { - "string-width": "^1.0.2 || 2" - } - }, - "wrap-ansi": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", - "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.0", - "string-width": "^3.0.0", - "strip-ansi": "^5.0.0" - }, - "dependencies": { - "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", - "dev": true - }, - "string-width": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", - "dev": true, - "requires": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" - } - }, - "strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", - "dev": true, - "requires": { - "ansi-regex": "^4.1.0" - } - } - } - }, - "wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", - "dev": true - }, - "y18n": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz", - "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==", - "dev": true - }, - "yargs": { - "version": "13.3.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz", - "integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==", - "dev": true, - "requires": { - "cliui": "^5.0.0", - "find-up": "^3.0.0", - "get-caller-file": "^2.0.1", - "require-directory": "^2.1.1", - "require-main-filename": "^2.0.0", - "set-blocking": "^2.0.0", - "string-width": "^3.0.0", - "which-module": "^2.0.0", - "y18n": "^4.0.0", - "yargs-parser": "^13.1.2" - }, - "dependencies": { - "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", - "dev": true - }, - "string-width": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", - "dev": true, - "requires": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" - } - }, - "strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", - "dev": true, - "requires": { - "ansi-regex": "^4.1.0" - } - } - } - }, - "yargs-parser": { - "version": "13.1.2", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz", - "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==", - "dev": true, - "requires": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" - } - }, - "yargs-unparser": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-1.6.0.tgz", - "integrity": "sha512-W9tKgmSn0DpSatfri0nx52Joq5hVXgeLiqR/5G0sZNDoLZFOr/xjBUDcShCOGNsBnEMNo1KAMBkTej1Hm62HTw==", - "dev": true, - "requires": { - "flat": "^4.1.0", - "lodash": "^4.17.15", - "yargs": "^13.3.0" - } - } - } -} diff --git a/tools/vscode-ext/package.json b/tools/vscode-ext/package.json deleted file mode 100644 index 1c1c965..0000000 --- a/tools/vscode-ext/package.json +++ /dev/null @@ -1,67 +0,0 @@ -{ - "name": "goc", - "displayName": "Goc Coverage", - "description": "Goc Coverage can display coverage vairation in real time. Goc is a comprehensive coverage testing system for The Go Programming Language, especially for some complex scenarios, like system testing code coverage collection and accurate testing.", - "version": "0.0.5", - "publisher": "lyyyuna", - "repository": { - "url": "https://github.com/qiniu/goc" - }, - "engines": { - "vscode": "^1.43.0" - }, - "categories": [ - "Other" - ], - "activationEvents": [ - "onLanguage:go" - ], - "main": "./out/extension.js", - "contributes": { - "commands": [ - { - "command": "extension.switch", - "title": "Enable/Disable coverage report" - } - ], - "configuration": { - "title": "Goc", - "properties": { - "goc.serverUrl": { - "type": "string", - "default": "http://127.0.0.1:7777", - "description": "Specify the goc server url." - }, - "goc.debug": { - "type": "boolean", - "default": false, - "description": "Turn on debug mode to log more details." - } - } - } - }, - "scripts": { - "vscode:prepublish": "npm run compile", - "compile": "tsc -p ./", - "watch": "tsc -watch -p ./", - "pretest": "npm run compile", - "test": "node ./out/test/runTest.js" - }, - "devDependencies": { - "@types/glob": "^7.1.1", - "@types/log4js": "^2.3.5", - "@types/mocha": "^5.2.7", - "@types/node": "^12.11.7", - "@types/vscode": "^1.43.0", - "glob": "^7.1.5", - "mocha": "^6.2.2", - "tslint": "^5.20.0", - "typescript": "^3.6.4", - "vscode-test": "^1.2.2" - }, - "dependencies": { - "axios": "^0.21.1", - "log4js": "^6.3.0", - "upath": "^1.2.0" - } -} diff --git a/tools/vscode-ext/src/extension.ts b/tools/vscode-ext/src/extension.ts deleted file mode 100644 index 5304cd6..0000000 --- a/tools/vscode-ext/src/extension.ts +++ /dev/null @@ -1,38 +0,0 @@ -// The module 'vscode' contains the VS Code extensibility API -// Import the module and reference it with the alias vscode in your code below -import * as vscode from 'vscode'; -import { GocServer } from './gocserver'; - -// this method is called when your extension is activated -// your extension is activated the very first time the command is executed -export function activate(context: vscode.ExtensionContext) { - - let gocStatusBarItem: vscode.StatusBarItem = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Left, 0); - gocStatusBarItem.text = 'Goc Coverage OFF'; - gocStatusBarItem.command = 'extension.switch'; - gocStatusBarItem.show(); - - let gocserver = new GocServer(); - - let disposable2 = vscode.commands.registerCommand('extension.switch', async () => { - if (gocStatusBarItem.text == 'Goc Coverage OFF') { - let err = gocserver.checkGoEnv() - // check if pc meets extension's requirement - if (err) { - vscode.window.showErrorMessage('Cannot get Golang version, please check your go environment.') - return - } - gocStatusBarItem.text = 'Goc Coverage ON'; - // get current project package structure - let packages = gocserver.getGoList(); - await gocserver.startQueryLoop(packages); - } else { - gocStatusBarItem.text = 'Goc Coverage OFF'; - gocserver.stopQueryLoop(); - } - }) - - context.subscriptions.push(disposable2); -} - -export function deactivate() {} diff --git a/tools/vscode-ext/src/gocserver.ts b/tools/vscode-ext/src/gocserver.ts deleted file mode 100644 index 19fa583..0000000 --- a/tools/vscode-ext/src/gocserver.ts +++ /dev/null @@ -1,212 +0,0 @@ -import axios from 'axios'; -axios.defaults.timeout = 3000; -import * as vscode from 'vscode'; -import { spawnSync } from 'child_process'; -import * as path from 'path'; -import { promisify } from 'util'; -import * as log4js from 'log4js'; -import * as upath from 'upath'; -const sleep = promisify(setTimeout); - -export class GocServer { - private _serverUrl: string = ''; - private _debug: Boolean = false; - private _logger: log4js.Logger = log4js.getLogger(); - private timer = true; - private highlightDecorationType = vscode.window.createTextEditorDecorationType({ - backgroundColor: 'green', - border: '2px solid white', - color: 'white' - });; - private lastProfile = ''; - private lastFileNeedsRender = ''; - - construct() { } - - async startQueryLoop(packages: any[]) { - this.timer = true; - while ( true === this.timer ) { - await sleep(2000); - - if ( true !== this.timer ) { - this.clearHightlight(); - return; - } - - this.getConfigurations(); - this.setDebugLogger(); - let profile = await this.getLatestProfile(); - this.renderFile(packages, profile); - } - } - - stopQueryLoop() { - this.timer = false; - this.lastProfile = ''; - this.lastFileNeedsRender = ''; - - this.clearHightlight() - } - - clearHightlight() { - vscode.window.visibleTextEditors.forEach(visibleEditor => { - visibleEditor.setDecorations(this.highlightDecorationType, []); - }); - } - - getConfigurations() { - this._serverUrl = vscode.workspace.getConfiguration().get('goc.serverUrl') || ''; - this._debug = vscode.workspace.getConfiguration().get('goc.debug') || false; - } - - setDebugLogger() { - if (this._debug == false) { - this._logger.level = "info"; - } else { - this._logger.level = "debug"; - } - - this._logger.info('goc server url: ', this._serverUrl); - } - - async getLatestProfile(): Promise { - let profileApi = `${this._serverUrl}/v1/cover/profile?force=true`; - - try { - let res = await axios.get(profileApi, ); - let body: string = res.data.toString(); - this._logger.debug(body); - return body; - } catch(err) { - this._logger.error(err.message); - } - - return ""; - } - - checkGoEnv() : Boolean { - let output = spawnSync('go', ['version']); - if (output.status != 0 || output.status == null) { - this._logger.error(output.stderr.toString()); - return true; - } - this._logger.debug('go version: ', output.stdout.toString()); - return false; - } - - getGoList(): Array { - let cwd = ""; - let workspaces = vscode.workspace.workspaceFolders || []; - if (workspaces.length == 0) { - this._logger.error("no workspace found"); - return []; - } else { - cwd = workspaces[0].uri.fsPath; - } - this._logger.debug('current project root directory: ', cwd); - let opts = { - 'cwd': cwd - }; - let output = spawnSync('go', ['list', '-json', './...'], opts); - if (output.status != 0 || output.status == null) { - this._logger.error(output.stderr.toString()); - return []; - } - let packages = JSON.parse('[' + output.stdout.toString().replace(/}\n{/g, '},\n{') + ']'); - return packages; - } - - renderFile(packages: Array, profile: string) { - let activeTextEditor = vscode.window.activeTextEditor; - let fileNeedsRender = activeTextEditor?.document.fileName || '---'; - - this._logger.debug('current active source code file: ', fileNeedsRender); - // check if needs to rerender - if (profile == this.lastProfile && fileNeedsRender == this.lastFileNeedsRender) { - return; - } - this.lastProfile = profile; - this.lastFileNeedsRender = fileNeedsRender; - - this._logger.debug('go list packages length: ', packages.length); - - for (let i=0; i { - vscode.window.showInformationMessage('Start all tests.'); - - test('Sample test', () => { - assert.equal(-1, [1, 2, 3].indexOf(5)); - assert.equal(-1, [1, 2, 3].indexOf(0)); - }); -}); diff --git a/tools/vscode-ext/src/test/suite/index.ts b/tools/vscode-ext/src/test/suite/index.ts deleted file mode 100644 index 2cd152c..0000000 --- a/tools/vscode-ext/src/test/suite/index.ts +++ /dev/null @@ -1,37 +0,0 @@ -import * as path from 'path'; -import * as Mocha from 'mocha'; -import * as glob from 'glob'; - -export function run(): Promise { - // Create the mocha test - const mocha = new Mocha({ - ui: 'tdd', - }); - mocha.useColors(true); - - const testsRoot = path.resolve(__dirname, '..'); - - return new Promise((c, e) => { - glob('**/**.test.js', { cwd: testsRoot }, (err, files) => { - if (err) { - return e(err); - } - - // Add files to the test suite - files.forEach(f => mocha.addFile(path.resolve(testsRoot, f))); - - try { - // Run the mocha test - mocha.run(failures => { - if (failures > 0) { - e(new Error(`${failures} tests failed.`)); - } else { - c(); - } - }); - } catch (err) { - e(err); - } - }); - }); -} diff --git a/tools/vscode-ext/tsconfig.json b/tools/vscode-ext/tsconfig.json deleted file mode 100644 index b65c745..0000000 --- a/tools/vscode-ext/tsconfig.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "compilerOptions": { - "module": "commonjs", - "target": "es6", - "outDir": "out", - "lib": [ - "es6" - ], - "sourceMap": true, - "rootDir": "src", - "strict": true /* enable all strict type-checking options */ - /* Additional Checks */ - // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ - // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ - // "noUnusedParameters": true, /* Report errors on unused parameters. */ - }, - "exclude": [ - "node_modules", - ".vscode-test" - ] -} diff --git a/tools/vscode-ext/tslint.json b/tools/vscode-ext/tslint.json deleted file mode 100644 index c81ff28..0000000 --- a/tools/vscode-ext/tslint.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "rules": { - "no-string-throw": true, - "no-unused-expression": true, - "no-duplicate-variable": true, - "curly": true, - "class-name": true, - "semicolon": [ - true, - "always" - ], - "triple-equals": true - }, - "defaultSeverity": "warning" -} diff --git a/tools/vscode-ext/vsc-extension-quickstart.md b/tools/vscode-ext/vsc-extension-quickstart.md deleted file mode 100644 index b510bff..0000000 --- a/tools/vscode-ext/vsc-extension-quickstart.md +++ /dev/null @@ -1,42 +0,0 @@ -# Welcome to your VS Code Extension - -## What's in the folder - -* This folder contains all of the files necessary for your extension. -* `package.json` - this is the manifest file in which you declare your extension and command. - * The sample plugin registers a command and defines its title and command name. With this information VS Code can show the command in the command palette. It doesn’t yet need to load the plugin. -* `src/extension.ts` - this is the main file where you will provide the implementation of your command. - * The file exports one function, `activate`, which is called the very first time your extension is activated (in this case by executing the command). Inside the `activate` function we call `registerCommand`. - * We pass the function containing the implementation of the command as the second parameter to `registerCommand`. - -## Get up and running straight away - -* Press `F5` to open a new window with your extension loaded. -* Run your command from the command palette by pressing (`Ctrl+Shift+P` or `Cmd+Shift+P` on Mac) and typing `Hello World`. -* Set breakpoints in your code inside `src/extension.ts` to debug your extension. -* Find output from your extension in the debug console. - -## Make changes - -* You can relaunch the extension from the debug toolbar after changing code in `src/extension.ts`. -* You can also reload (`Ctrl+R` or `Cmd+R` on Mac) the VS Code window with your extension to load your changes. - - -## Explore the API - -* You can open the full set of our API when you open the file `node_modules/@types/vscode/index.d.ts`. - -## Run tests - -* Open the debug viewlet (`Ctrl+Shift+D` or `Cmd+Shift+D` on Mac) and from the launch configuration dropdown pick `Extension Tests`. -* Press `F5` to run the tests in a new window with your extension loaded. -* See the output of the test result in the debug console. -* Make changes to `src/test/suite/extension.test.ts` or create new test files inside the `test/suite` folder. - * The provided test runner will only consider files matching the name pattern `**.test.ts`. - * You can create folders inside the `test` folder to structure your tests any way you want. - -## Go further - - * Reduce the extension size and improve the startup time by [bundling your extension](https://code.visualstudio.com/api/working-with-extensions/bundling-extension). - * [Publish your extension](https://code.visualstudio.com/api/working-with-extensions/publishing-extension) on the VSCode extension marketplace. - * Automate builds by setting up [Continuous Integration](https://code.visualstudio.com/api/working-with-extensions/continuous-integration).