[
  {
    "path": ".github/ISSUE_TEMPLATE/problem-or-bug.md",
    "content": "---\nname: problem or bug\nabout: I have a problem with docker-pushrm\ntitle: ''\nlabels: ''\nassignees: ''\n\n---\n\n**Describe the problem or bug**\nA clear and concise description of what the problem or bug is, including all steps necessary to reproduce it.\n\n**docker-pushrm version**\ncheck version with:\n- as Docker CLI plugin: `docker --help | grep pushrm`\n- as standalone: `docker-pushrm docker-cli-plugin-metadata | grep -i version`\n\n**Docker CLI version and platform**\ncheck with: `docker version`\nif on Linux, what distro and distro version are you running? (example: Fedora 32)\n\n**if possible: registry server version**\nexample: *self-hosted `harbor` version 2.0.0*\n\n**exact command that you're running**\nexample: `docker pushrm --provider quay quay.io/my-user/my-repo`\n\n**debug output**\nre-run that command with `--debug` flag and paste the output here\n(i.e.: `docker pushrm --provider quay quay.io/my-user/my-repo --debug`)\n\n**Additional context**\nAdd any other context about the problem here.\n"
  },
  {
    "path": ".github/workflows/release.yml",
    "content": "name: Release\non:\n  push:\n    # Sequence of patterns matched against refs/tags\n    tags:\n      - 'v*' # Push events to matching v*, i.e. v1.0, v20.15.10\n\njobs:\n  pre:\n   name: pre\n   runs-on: ubuntu-latest\n   steps:\n     - name: pre1\n       run: |\n         env\n         exit 0\n       \n  cr_release:\n    name: create_release\n    needs: [pre] #don't create a release too early\n    runs-on: ubuntu-latest\n    steps:\n    - name: Check out code for changelog creation\n      uses: actions/checkout@v2\n      with:\n        fetch-depth: 0 #otherwise only one commit is fetched\n    - name: Create Changelog\n      id: create_changelog\n      run: |\n        git fetch --tags\n        git tag #for debug\n        git log --oneline #for debug\n        previousTag=$(git tag --sort=-v:refname | head -2 | tail -1)\n        echo previous tag: $previousTag #for debug\n        changelog=$(git log --oneline --pretty=\"%s\" $previousTag..HEAD)\n        echo changelog1: \"$changelog\" #for debug\n        changelog=$(echo \"$changelog\" | sed 's/^/- /')\n        echo changelog2: \"$changelog\" #for debug\n        echo changes since $previousTag: > ./changelog.md\n        echo \"$changelog\" >> ./changelog.md\n    - name: Create Release\n      id: create_release\n      uses: actions/create-release@v1\n      env:\n        GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # token provided by Actions, no need to set it\n      with:\n        tag_name: ${{ github.ref }}\n        release_name: Release ${{ github.ref }}\n        draft: true #we'll undraft at the end if the build step was successfull (= all assets uploaded to the release)\n        prerelease: false\n        body_path: ./changelog.md\n    - name: Output Release URL File\n      run: echo \"${{ steps.create_release.outputs.upload_url }}\" > release_url.txt\n    - name: Save Release URL File for publish\n      uses: actions/upload-artifact@v1\n      with:\n        name: release_url\n        path: ./release_url.txt\n    - name: Output Release ID File\n      run: echo \"${{ steps.create_release.outputs.id }}\" > release_id.txt\n    - name: Save Release ID File for publish\n      uses: actions/upload-artifact@v1\n      with:\n        name: release_id\n        path: ./release_id.txt\n        \n  build:\n    needs: [pre, cr_release]\n    strategy:\n      matrix:\n        os: [linux, darwin, windows]\n        arch: [amd64, 386, arm64, arm]\n        exclude:\n          - os: windows\n            arch: arm64\n          - os: windows\n            arch: arm\n          - os: darwin\n            arch: arm\n          - os: darwin\n            arch: 386\n        include:\n          - os: windows\n            file_extension: '.exe'\n          - os: windows\n            ci_image: ubuntu-latest\n          - os: linux\n            file_extension: ''\n          - os: linux\n            ci_image: ubuntu-latest\n          - os: darwin\n            file_extension: ''\n          - os: darwin\n            ci_image: macos-latest\n          - os: darwin\n            no_upx: true\n    name: Build\n    runs-on: ${{ matrix.ci_image }}\n    env: \n      GOOS: ${{ matrix.os }}\n      GOARCH: ${{ matrix.arch }}\n    steps:\n\n    - name: Set up Go 1.16\n      uses: actions/setup-go@v2\n      with:\n        go-version: 1.16\n      id: go\n\n    - name: Check out code into the Go module directory\n      uses: actions/checkout@v2\n\n    - name: Get dependencies\n      env:\n        GOOS: ${{ matrix.os }}\n        GOARCH: ${{ matrix.arch }}\n        CGO_ENABLED: 0\n      run: |\n        go get -v -t -d .\n\n    - name: Build\n      run: go build -v -a -tags netgo -ldflags='-s -w -extldflags \"-static\"' .\n\n    - name: compress with upx\n      if: ${{ matrix.no_upx != true }}\n      run: sudo apt-get -y update && sudo apt-get -y install upx && upx ./docker-pushrm${{ matrix.file_extension }}\n\n    - name: Import darwin code-signing certificates\n      if: ${{ matrix.os == 'darwin' }}\n      uses: Apple-Actions/import-codesign-certs@v1\n      with:\n        p12-file-base64: ${{ secrets.APPLE_DEVELOPER_CERTIFICATE_P12_BASE64 }} #dev id cert as b64\n        p12-password: ${{ secrets.APPLE_DEVELOPER_CERTIFICATE_PASSWORD }} #pw for cert\n\n    - name: Sign darwin binary with Gon\n      if: ${{ matrix.os == 'darwin' }}\n      env:\n        AC_USERNAME: ${{ secrets.AC_USERNAME }} #apple id\n        AC_PASSWORD: ${{ secrets.AC_PASSWORD }} #app specific pw for apple id\n      run: |\n        brew tap mitchellh/gon\n        brew install mitchellh/gon/gon\n        gon -log-level=debug -log-json ./gon.json\n        rm -f ./docker-pushrm\n        unzip docker-pushrm\n\n    - name: Upload artifact\n      uses: actions/upload-artifact@v1\n      with:\n        name: docker-pushrm_${{ matrix.os }}_${{ matrix.arch }}${{ matrix.file_extension }}\n        path: ./docker-pushrm${{ matrix.file_extension }}\n\n    - name: Load Release URL File from release job\n      uses: actions/download-artifact@v1\n      with:\n          name: release_url\n    - name: Get Release File Name & Upload URL\n      id: get_release_info\n      run: |\n        value=`cat release_url/release_url.txt`\n        echo ::set-output name=upload_url::$value\n\n    - name: Upload Release Asset\n      id: upload-release-asset\n      uses: actions/upload-release-asset@v1.0.1\n      env:\n        GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n      with:\n        upload_url: ${{ steps.get_release_info.outputs.upload_url }} # references get_release_info step above\n        asset_name: docker-pushrm_${{ matrix.os }}_${{ matrix.arch }}${{ matrix.file_extension }}\n        asset_path: ./docker-pushrm${{ matrix.file_extension }}\n        asset_content_type: application/octet-stream\n  \n  cr_darwin_universal_binary:\n    needs: [build]\n    runs-on: macos-latest\n    steps:\n\n    - name: Check out code\n      uses: actions/checkout@v2\n\n    - name: Download darwin_amd64 artifact\n      uses: actions/download-artifact@v1\n      with:\n          name: docker-pushrm_darwin_amd64\n    \n    - name: Download darwin_arm64 artifact\n      uses: actions/download-artifact@v1\n      with:\n          name: docker-pushrm_darwin_arm64\n    \n    - name: package darwin universal binary\n      run: |\n        lipo -create docker-pushrm_darwin_arm64/docker-pushrm docker-pushrm_darwin_amd64/docker-pushrm -output docker-pushrm\n    \n    - name: Import darwin code-signing certificates\n      uses: Apple-Actions/import-codesign-certs@v1\n      with:\n        p12-file-base64: ${{ secrets.APPLE_DEVELOPER_CERTIFICATE_P12_BASE64 }} #Apple Dev ID cert as b64\n        p12-password: ${{ secrets.APPLE_DEVELOPER_CERTIFICATE_PASSWORD }} #pw for cert\n\n    - name: Sign darwin binary with Gon\n      env:\n        AC_USERNAME: ${{ secrets.AC_USERNAME }} #apple id\n        AC_PASSWORD: ${{ secrets.AC_PASSWORD }} #app specific pw for apple id\n      run: |\n        brew tap mitchellh/gon\n        brew install mitchellh/gon/gon\n        gon -log-level=debug -log-json ./gon.json\n        rm -f ./docker-pushrm\n        unzip docker-pushrm\n\n    - name: Upload artifact\n      uses: actions/upload-artifact@v1\n      with:\n        name: docker-pushrm_darwin_universal2\n        path: ./docker-pushrm\n\n    - name: Load Release URL File from release job\n      uses: actions/download-artifact@v1\n      with:\n          name: release_url\n  \n    - name: Get Release File Name & Upload URL\n      id: get_release_info\n      run: |\n        value=`cat release_url/release_url.txt`\n        echo ::set-output name=upload_url::$value\n\n    - name: Upload Release Asset\n      id: upload-release-asset\n      uses: actions/upload-release-asset@v1.0.1\n      env:\n        GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n      with:\n        upload_url: ${{ steps.get_release_info.outputs.upload_url }} # references get_release_info step above\n        asset_name: docker-pushrm_darwin_universal2\n        asset_path: ./docker-pushrm\n        asset_content_type: application/octet-stream\n\n  \n  build_containers:\n    #needs: [build]\n    runs-on: ubuntu-latest\n    steps:\n    - name: Check out code\n      uses: actions/checkout@v2\n    - name: Split tag string into semantic version parts\n      id: semver\n      run: |\n        git fetch --tags\n        git tag #for debug\n        export vcur=$(git tag --sort=-v:refname | head -1 | sed 's/v//1')\n        export vmajor=$(echo $vcur | cut -d. -f1)\n        export vminor=$(echo $vcur | cut -d. -f2)\n        export vpatch=$(echo $vcur | cut -d. -f3)\n        echo ::set-output name=vcur::$vcur\n        echo ::set-output name=vmajor::$vmajor\n        echo ::set-output name=vminor::$vminor\n        echo ::set-output name=vpatch::$vpatch\n        echo version: $vcur\n        echo version major: $vmajor\n        echo version minor: $vminor\n        echo version patch: $vpatch\n    - name: Prepare docker-buildx\n      run: |\n        docker run --rm --privileged multiarch/qemu-user-static --reset -p yes\n        docker buildx create --name mybuilder\n        docker buildx ls #for debug\n        docker buildx inspect --bootstrap\n        docker buildx use mybuilder\n    - name: Docker login\n      env:\n        DOCKER_USER: chko\n        DOCKER_PASS: ${{ secrets.DOCKER_PASS }}\n      run: |\n        docker login -u \"$DOCKER_USER\" -p  \"$DOCKER_PASS\"\n    - name: Build and Push container images with docker-buildx\n      env:\n        vcur: ${{ steps.semver.outputs.vcur }}\n        vmajor: ${{ steps.semver.outputs.vmajor }}\n        vminor: ${{ steps.semver.outputs.vminor }}\n        vpatch: ${{ steps.semver.outputs.vpatch }}\n      run: |\n        docker buildx inspect #for debug\n        echo version: $ver - major: $vmajor - minor: $vminor - patch: $vpatch #for debug\n        destrepo=chko/docker-pushrm\n        docker buildx build -t \"$destrepo:latest\" -t \"$destrepo:$vcur\" -t \"$destrepo:$vmajor\" --platform linux/amd64,linux/386,linux/arm64,linux/arm/v7,linux/arm/v6 --push .\n        docker buildx stop\n    - name: Update container repo README\n      env:\n        #exact env var names for docker-pushrm\n        DOCKER_USER: chko\n        DOCKER_PASS: ${{ secrets.DOCKER_PASS }}\n      run: |\n        # download latest docker-pushrm release from github\n        # (because we keep the release that this workflow creates drafted until the end of the workflow run the version we're downloading is NOT the one we're currently releasing)\n        export FILENAME=docker-pushrm_linux_amd64 && export DESTDIR=. && DOWNLOAD_URL=$(curl --silent --fail --show-error https://api.github.com/repos/christian-korneck/docker-pushrm/releases/latest | jq -r \".assets | map(select(.name == \\\"$FILENAME\\\"))[0].browser_download_url\") && curl --silent --fail --show-error -L $DOWNLOAD_URL -o \"$DESTDIR/docker-pushrm\" && chmod +rx \"$DESTDIR/docker-pushrm\"\n        # this automatically uses README-containers.md\n        ./docker-pushrm --short \"Docker Push Readme - Update the docs of your container repo on Dockerhub, Quay, Harbor from a file\" chko/docker-pushrm\n\n  undraft_release:\n    needs: [build, build_containers, cr_darwin_universal_binary] #only undraft the release when assets were uploaded\n    runs-on: ubuntu-latest\n    steps:\n    - name: Load Release ID File from release job\n      uses: actions/download-artifact@v1\n      with:\n          name: release_id\n    - name: Get Release ID\n      id: get_release_id_info\n      run: |\n        value=`cat release_id/release_id.txt`\n        echo ::set-output name=release_id::$value\n    - name: Undraft release\n      id: undraft_release\n      env:\n        GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n        RELEASE_ID: ${{ steps.get_release_id_info.outputs.release_id }} # references other step\n      run: |\n        curl --verbose --fail --show-error --location --request PATCH \"https://api.github.com/repos/$GITHUB_REPOSITORY/releases/$RELEASE_ID\" --header \"Authorization: token $GITHUB_TOKEN\" --header 'Content-Type: application/json' --header 'Accept: application/vnd.github.everest-preview+json' --data-raw '{\"draft\": false}'\n  \n  cleanup:\n    needs: [build, cr_darwin_universal_binary] #currently this can start before build_containers is finished\n    if: always()\n    runs-on: ubuntu-latest\n    steps:\n    - name: call webhook to delete artifacts\n      env:\n        FOR_WEBHOOKS_SECRET: ${{ secrets.FOR_WEBHOOKS_SECRET }}\n      run: |\n        echo \"::add-mask::$FOR_WEBHOOKS_SECRET\"\n        curl --verbose --fail --show-error --location --request POST \"https://api.github.com/repos/$GITHUB_REPOSITORY/dispatches\" --header \"Authorization: token $FOR_WEBHOOKS_SECRET\" --header 'Content-Type: application/json' --header 'Accept: application/vnd.github.everest-preview+json' --data-raw \"{ \\\"event_type\\\": \\\"delete_all_artifacts\\\", \\\"client_payload\\\": {\\\"parent_runid\\\": \\\"$GITHUB_RUN_ID\\\", \\\"parent_repo\\\": \\\"$GITHUB_REPOSITORY\\\"} }\"\n"
  },
  {
    "path": ".github/workflows/webhook_target.yml",
    "content": "name: delete calling job's artifacts\non: repository_dispatch\njobs:\n  main:\n    runs-on: ubuntu-latest\n    steps:\n    - name: Delete artifacts\n      if: github.event.action == 'delete_all_artifacts'\n      uses: christian-korneck/delete-run-artifacts-action@v1\n      env:\n        GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n      with:\n        parent_runid: ${{ github.event.client_payload.parent_runid  }}\n        parent_repo: ${{ github.event.client_payload.parent_repo }}"
  },
  {
    "path": ".gitignore",
    "content": "# Binaries for programs and plugins\n*.exe\n*.exe~\n*.dll\n*.so\n*.dylib\n/docker-pushrm\n\n# Test binary, built with `go test -c`\n*.test\n\n# Output of the go coverage tool, specifically when used with LiteIDE\n*.out\n\n# Dependency directories (remove the comment below to include it)\n# vendor/\n"
  },
  {
    "path": "Dockerfile",
    "content": "FROM golang:1.16-alpine AS builder\nWORKDIR /go/src/github.com/christian-korneck/docker-pushrm\nCOPY . .\nRUN apk add --no-cache ca-certificates && update-ca-certificates\nENV CGO_ENABLED 0\nRUN go build -v -a -tags netgo -ldflags='-s -w -extldflags \"-static\"' .\n#RUN apk add --no-cache upx && upx ./docker-pushrm\n\nFROM docker.io/library/busybox\nCOPY --from=builder /go/src/github.com/christian-korneck/docker-pushrm/docker-pushrm /\nCOPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/\n\n#nobody:nogroup\nUSER 65534:65534\nENTRYPOINT [\"/docker-pushrm\"]\n"
  },
  {
    "path": "LICENSE",
    "content": "MIT License\n\nCopyright (c) 2020 Christian Korneck\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "README-containers.md",
    "content": "# Docker Push Readme\n\nThis is a container image of [`docker-pushrm`](https://github.com/christian-korneck/docker-pushrm), a tool that lets you update the README of your container repo on Dockerhub, Quay or Harbor from a local markdown file.\n\n![hello moon](https://raw.githubusercontent.com/christian-korneck/docker-pushrm/master/assets/container_registries.png)\n\n## About this tool\n\nCheck the [full docs](https://github.com/christian-korneck/docker-pushrm/blob/master/README.md) for an introduction.\n\n## How to use this container image\n\n### Examples\n\n#### Push a README file to Dockerhub\n\n```\n$ ls\nREADME.md\n\n$ docker run --rm -t \\\n-v $(pwd):/myvol \\\n-e DOCKER_USER='my-user' -e DOCKER_PASS='my-pass' \\\nchko/docker-pushrm:1 --file /myvol/README.md \\ \n--short \"My short description\" --debug my-user/my-repo\n\n...\nDEBU content validation successfull, readme successfully pushed to repo server\n```\n\nLet's dissect this a bit:\n\n- we pin to the major version (`v1`) of this image (`chko/docker-pushrm:v1`). Recommended for most use cases.\n- the README file is in the current working directory on the host. We map this dir as volume to the container (mounted at `/myvol`)\n- we tell *docker-pushrm* where to find the README file with `--file <path>`\n- our destination repo on Dockerhub is `my-user/my-repo`\n- we pass the credentials for the repo as environment variables to the container (`DOCKER_USER` and `DOCKER_PASS`)\n- we set `--debug` to get additional log output (optional)\n- we set the short description for the Dockerhub repo with `--short <string>` (optional)\n\n**Alternatively all params can also get set with environment variables:**\n\n```\n$ docker run --rm -t \\\n-v $(pwd):/myvol \\\n-e DOCKER_USER='my-user' -e DOCKER_PASS='my-pass' \\\n-e PUSHRM_PROVIDER=dockerhub -e PUSHRM_FILE=/myvol/README.md \\\n-e PUSHRM_SHORT='my short description' \\\n-e PUSHRM_TARGET=docker.io/my-user/my-repo -e PUSHRM_DEBUG=1 \\\nchko/docker-pushrm:1\n```\n\n#### Push a README file to a Harbor v2 registry server\n\nUse the `--provider harbor2` flag:\n\n```\n$ ls\nREADME.md\n\n$ docker run --rm -t \\\n-v $(pwd):/myvol \\\n-e DOCKER_USER='my-user' -e DOCKER_PASS='my-pass' \\\nchko/docker-pushrm:1 --file /myvol/README.md \\ \n--provider harbor2 --debug demo.goharbor.io/my-project/my-repo\n```\n\n#### Push a README file to Quay.io or a Quay registry server\n\n\n- use the `--provider quay` flag\n- use env var `APIKEY__<SERVER>_<DOMAIN>` or `DOCKER_APIKEY` for apikey credentials\n\n```\n$ ls\nREADME.md\n\n$ docker run --rm -t \\\n-v $(pwd):/myvol \\\n-e APIKEY__QUAY_IO='my-apikey' \\\nchko/docker-pushrm:1 --file /myvol/README.md \\ \n--provider quay --debug quay.io/my-user/my-repo\n```\n\n### env vars\n\n| env var                     | example value                  | description\n| --------------------------- | ------------------------------ | ----------------------------------------\n| `DOCKER_USER`               | `my-user`                      | login username\n| `DOCKER_PASS`               | `my-password`                  | login password\n| `DOCKER_APIKEY`             | `my-quay-api-key`              | quay api key\n| `APIKEY__<SERVER>_<DOMAIN>` | `my-quay-api-key`              | quay api key (alternative)\n| `PUSHRM_PROVIDER`           | `dockerhub`, `quay`, `harbor2` | repo provider type\n| `PUSHRM_SHORT`              | `my short description`         | set/update repo short description\n| `PUSHRM_FILE`               | `/myvol/README.md`             | path to the README file\n| `PUSHRM_DEBUG`              | `1`                            | enable verbose output\n| `PUSHRM_CONFIG`             | `/myvol/.docker/config.json`   | Docker config file (for credentials)\n| `PUSHRM_TARGET`             | `docker.io/my-user/my-repo`    | container repo ref\n\nPresedence:\n- Params specified with flags take precedence over env vars.\n- Login env vars take precedence over credentials from a Docker config file\n\n\n\n\n\n"
  },
  {
    "path": "README.md",
    "content": "# Docker Push Readme\n\nUpdate the README of your container repo on Dockerhub, Quay or Harbor with a simple Docker command:\n\n```\n$ ls\nREADME.md\n$ docker pushrm my-user/hello-world\n```\n\n![hello moon](assets/container_registries.png)\n\n## About\n\n`docker-pushrm` is a Docker CLI plugin that adds a new `docker pushrm` (speak: *\"push readme\"*) command to Docker.\n\nIt pushes the README file from the current working directory to a container registry server where it appears as repo description in the webinterface.\n\nIt currently supports **[Dockerhub](https://hub.docker.com)** (cloud), **Red Hat Quay** ([cloud](https://quay.io) and [self-hosted](https://www.openshift.com/products/quay)/OpenShift) and **[Harbor v2](https://goharbor.io)** (self-hosted).\n\nFor most registry types `docker-pushrm` uses authentication info from the Docker credentials store - so it \"just works\" for registry servers that you're already logged into with Docker.\n\n(For some other registry types, you'll need to pass an API key via env var or config file).\n\n## Usage example\n\nLet's build a container image, push it to Dockerhub and then also push the README to Dockerhub:\n\n```\n$ ls\nDockerfile\tREADME.md\n$ docker login\nUsername: my-user\nPassword: ********\nLogin Succeeded\n$ docker build -t my-user/hello-world .\n$ docker push my-user/hello-world\n$ docker pushrm my-user/hello-world\n```\n\nWhen we now browse to the repo in the Dockerhub webinterface we should find the repo's README to be updated with the contents of the local README file.\n\nThe same works for Harbor version 2 registry servers:\n\n```\ndocker pushrm --provider harbor2 demo.goharbor.io/myproject/hello-world\n```\n\nAnd also for Quay/OpenShift cloud and self-hosted registry servers:\n```\ndocker pushrm --provider quay quay.io/my-user/hello-world\n```\n\nFor Dockerhub it's also possible to set the repo's short description with `-s \"some description\"`.\n\nIn case that you want different content to appear in the README on the container registry than on the git repo (for github/gitlab), you can create a dedicated `README-containers.md`, which takes precedence. It's also possible to specify a path to a README file with `--file <path>`.\n\n## Installation\n\n- make sure Docker or Docker Desktop is installed\n- Download `docker-pushrm` for your platform from the [release page](https://github.com/christian-korneck/docker-pushrm/releases/latest).\n- copy it to:\n  - Windows: `c:\\Users\\<your-username>\\.docker\\cli-plugins\\docker-pushrm.exe`\n  - Mac + Linux: `$HOME/.docker/cli-plugins/docker-pushrm`\n- on Mac/Linux make it executable: `chmod +x $HOME/.docker/cli-plugins/docker-pushrm`\n\nNow you should be able to run `docker pushrm --help`.\n\n## Running `docker-pushrm` as a container\n\nThere's also a Docker/OCI [container image](https://hub.docker.com/r/chko/docker-pushrm) of this tool. See [separate docs](README-containers.md) for how to use it. This is mainly intended for use in CI workflows.\n\n## Use with github actions\n\nThis tool is also available as a github action [here](https://github.com/marketplace/actions/update-container-description-action).\n\n## Use with GitLab CI/CD\n\nHere's an example for a `.gitlab-ci.yml` that uses the `docker-pushrm` container image. (`DOCKER_USER` and `DOCKER_PASS` need to be set as project or group variables):\n\n```\nstages:\n  - release\n\npushrm:\n  stage: release\n  image:\n    name: chko/docker-pushrm\n    entrypoint: [\"/bin/sh\", \"-c\", \"/docker-pushrm\"]\n  variables:\n    DOCKER_USER: $DOCKER_USER\n    DOCKER_PASS: $DOCKER_PASS\n    PUSHRM_SHORT: My short description\n    PUSHRM_TARGET: docker.io/$DOCKER_USER/my-repo\n    PUSHRM_DEBUG: 1\n    PUSHRM_FILE: $CI_PROJECT_DIR/README.md\n  script: \"/bin/true\"\n```\n\n(Note: The above `entrypoint`/`script` setup is a workaround for a [GitLab limitation](https://gitlab.com/gitlab-org/gitlab-runner/-/issues/26501). For the same reason the `docker-pushrm` container images include [busybox](https://hub.docker.com/_/busybox)).\n\n## How to log in to container registries\n\n### Log in to Dockerhub registry\n\n```\ndocker login\n```\n\nBoth password and Personal Access Token (PAT) should work. When using a PAT, make sure it has sufficient privileges (`admin` scope).\n\n### Log in to Harbor v2 registry\n\nIn the Harbor webinterface, create a `Robot Account` for your project with (at least) the privilege `repository`: `update` [[screenshot](https://github.com/christian-korneck/docker-pushrm/issues/10#issuecomment-2159212629)] and use the displayed username and password.\n\n(Login with a regular Harbor user account instead is possible too, but [won't work](https://github.com/christian-korneck/docker-pushrm/issues/10) if the Harbor instance is using OIDC auth. Using a robot account is strongly recommended).\n\n\n```\ndocker login <servername>\n```\n\nExample:\n```\ndocker login demo.goharbor.io\n```\n\n### Log in to Quay registry\n\nIf you want to be able to push containers, you need to log in as usual:\n\n- for Quay cloud: `docker login quay.io`\n- for self-hosted Quay server or OpenShift: `docker login <servername>` (example: `docker login my-server.com`)\n\nIn addition to be able to use `docker-pushrm` you need to set up an API key:\n\nFirst, log into the Quay webinterface and create an API key:\n- if you don't have an organization create a new organization (your repos don't need to be under the organization's namespace, this is just to unlock the \"apps\" settings page)\n- navigate to the org and open the `applications` tab\n- `create new app` and give it some name\n- click on the app name and open to the `generate token` tab\n- create a token with permissions `Read/Write to any accessible repositories`\n- after confirming you should now see the token secret. Write it down in a safe place.\n\n(Refer to the Quay docs for more info)\n\nThen, make the API key available to `docker-pushrm`. There are two options for that: Either set an environment variable (recommended for CI) or add it to the Docker config file (recommended for Desktop use). (If both are present, the env var takes precedence).\n\n#### env var for Quay API key\nset an environment variable `DOCKER_APIKEY=<apikey>` or `APIKEY__<SERVERNAME>_<DOMAIN>=<apikey>`\n\nexample for servername `quay.io`:\n```\nexport APIKEY__QUAY_IO=my-api-key\ndocker pushrm quay.io/my-user/my-repo\n```\n\n#### configure Quay API key in Docker config file\n\nIn the Docker config file (default: `$HOME/.docker/config.json`) add a json key `plugins.docker-pushrm.apikey_<servername>` with the api key as string value.\n\nExample for servername `quay.io`:\n\n```\n{\n\n  ...,\n\n\n  \"plugins\" : {\n    \"docker-pushrm\" : {\n      \"apikey_quay.io\" : \"my-api-key\"\n    }\n  },\n\n  ...\n}\n```\n\n## Log in with environment variables (for CI)\n\nAlternatively credentials can be set as environment variables. Environment variables take precedence over the Docker credentials store. Environment variables can be specified with or without a server name. The variant without a server name takes precedence.\n\nThis is intended for running `docker-pushrm` as a standalone tool in a CI environment (no full Docker installation needed).\n\n- `DOCKER_USER` and `DOCKER_PASS`\n- `DOCKER_USER__<SERVER>_<DOMAIN>` and `DOCKER_PASS__<SERVER>_<DOMAIN>`\n\t(example for server `docker.io`: `DOCKER_USER__DOCKER_IO=my-user` and `DOCKER_PASS__DOCKER_IO=my-password`)\n\nThe provider 'quay' needs an additional env var for the API key in form of `APIKEY__<SERVERNAME>_<DOMAIN>=<apikey>`.\n\nExample:\n\n```\nDOCKER_USER=my-user DOCKER_PASS=mypass docker-pushrm my-user/my-repo\n```\n\n\n## What if I use [podman, img, k3c, buildah, ...] instead of Docker?\n\nYou can still use `docker-pushrm` as standalone executable.\n\nThe only obstacle is that you need to provide it credentials in the Docker style.\n\nThe easiest way for that is to set up a minimal Docker config file with the registry server logins that you need. (Alternatively credentials can be passed [in environment variables](#log-in-with-environment-variables-for-ci) )\n\nYou can either create this config file on a computer with Docker installed (by running `docker login` and then copying the `$HOME/.docker/config.json` file).\n\nOr alternatively you can also set it up manually. Here's an example:\n\n```\n{\n\t\"auths\": {\n\t\t\"https://index.docker.io/v1/\": {\n\t\t\t\"auth\": \"xxx\"\n\t\t},\n        \"https://demo.goharbor.io\": {\n\t\t\t\"auth\": \"xxx\"\n\t\t}\n\n\t},\n}\n```\nThe auth value is base64 of `<user>:<passwd>` (i.e. `myuser:mypasswd`)\n\nIt's also possible to use Docker [credential helpers](https://docs.docker.com/engine/reference/commandline/login/#credential-helpers) on systems that don't have Docker installed to avoid clear text passwords in the config file. The credential helper needs to be configured in the Docker config file and the credential helper executable needs to be in the `PATH`. (Check the Docker docs for details).\n\n## Can you add support for registry [XY...]?\n\nPlease open an issue.\n\n## Installation for all users\n\nTo install the plugin for all users of a system copy it to the following path (instead of to the user home dir). Requires admin/root privs.\n\n- Linux: depending on the distro, either `/usr/lib/docker/cli-plugins/docker-pushrm` or `/usr/libexec/docker/cli-plugins/docker-pushrm`\n- Windows: `%ProgramData%\\Docker\\cli-plugins\\docker-pushrm.exe`\n- Mac: `/Applications/Docker.app/Contents/Resources/cli-plugins/docker-pushrm`\n\nOn Mac/Linux make it executable and readable for all users: `chmod a+rx <path>/docker-pushrm`\n\n## Using env vars instead of cmdline params\n\nAll cmdline parameters can also be set as env vars with prefix `PUSHRM_`.    \n    \nCmdline parameters take precedence over env vars. (Except for login env vars, which take precedence over the local credentials store).    \n    \nThis is mainly intended for running this tool in a container in [12fa](https://12factor.net/config) style.    \n    \nA list of all supported env vars is [here](README-containers.md#env-vars).\n\n## Limitations\n\n(currently none)\n\n----\nAll trademarks, logos and website designs belong to their respective owners.\n"
  },
  {
    "path": "cmd/docker-cli-plugin-metadata.go",
    "content": "/*\nCopyright © 2020 Christian Korneck <christian@korneck.de>\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n*/\n\npackage cmd\n\nimport (\n\t\"encoding/json\"\n\t\"os\"\n\n\t\"github.com/spf13/cobra\"\n)\n\n// dockerCliPluginMetadataCmd represents the dockerCliPluginMetadata command\nvar dockerCliPluginMetadataCmd = &cobra.Command{\n\tUse:   \"docker-cli-plugin-metadata\",\n\tShort: \"provides plugin metadata to the docker cli\",\n\tLong: `provides plugin metadata to the docker cli\n\t\n\t`,\n\tRun: func(cmd *cobra.Command, args []string) {\n\t\tenc := json.NewEncoder(os.Stdout)\n\t\tenc.SetIndent(\"\", \"    \")\n\t\t// specs: https://docs.docker.com/engine/extend/cli_plugins/#the-docker-cli-plugin-metadata-subcommand\n\t\td := map[string]string{\"SchemaVersion\": \"0.1.0\", \"Vendor\": \"Christian Korneck\", \"Version\": \"1.9.0\", \"ShortDescription\": \"Push Readme to container registry\"}\n\t\tenc.Encode(d)\n\t},\n}\n\nfunc init() {\n\trootCmd.AddCommand(dockerCliPluginMetadataCmd)\n\tdockerCliPluginMetadataCmd.Hidden = true\n\n\t// Here you will define your flags and configuration settings.\n\n\t// Cobra supports Persistent Flags which will work for this command\n\t// and all subcommands, e.g.:\n\t// dockerCliPluginMetadataCmd.PersistentFlags().String(\"foo\", \"\", \"A help for foo\")\n\n\t// Cobra supports local flags which will only run when this command\n\t// is called directly, e.g.:\n\t// dockerCliPluginMetadataCmd.Flags().BoolP(\"toggle\", \"t\", false, \"Help message for toggle\")\n}\n"
  },
  {
    "path": "cmd/pushrm.go",
    "content": "/*\nCopyright © 2020 Christian Korneck <christian@korneck.de>\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n*/\n\npackage cmd\n\nimport (\n\t\"errors\"\n\t\"os\"\n\t\"regexp\"\n\t\"strings\"\n\t\"unicode/utf8\"\n\n\t\"github.com/christian-korneck/docker-pushrm/provider/dockerhub\"\n\t\"github.com/christian-korneck/docker-pushrm/provider/harbor2\"\n\t\"github.com/christian-korneck/docker-pushrm/provider/provider\"\n\t\"github.com/christian-korneck/docker-pushrm/provider/quay\"\n\t\"github.com/christian-korneck/docker-pushrm/util\"\n\tlog \"github.com/sirupsen/logrus\"\n\t\"github.com/spf13/cobra\"\n\t\"github.com/spf13/viper\"\n)\n\nvar providername string\nvar rfile string\nvar shortdesc string\n\n// pushrmCmd represents the pushrm command\nvar pushrmCmd = &cobra.Command{\n\tUse:     \" NAME[:TAG]\",\n\tAliases: []string{\"pushrm\"},\n\tArgs:    cobra.MaximumNArgs(1),\n\tShort:   \"push README file from current working directory to container registry (Dockerhub, quay, harbor2)\",\n\tLong: `help for docker pushrm\n\n\tdocker pushrm NAME[:TAG] [flags]\n\n\tpushes the README.md file from the current working\n\tdirectory to the container registry (Dockerhub, quay, harbor2)\n\twhere it appears as repo description.\n\n\n\n\tUsage Examples:\n\t===============\n\n\n\tDockerhub (hub.docker.com cloud)\n\t--------------------------------\n\tdocker pushrm myaccount/hello-world\n\tdocker pushrm docker.io/my-account/hello-world\n\n\n\tQuay (quay.io cloud or self-hosted)\n\t-----------------------------------\n\tdocker pushrm quay.io/my-organization/hello-world\n\tdocker pushrm --provider quay my-quay-server.com/my-user/hello-world\n\n\n\tHarbor (self-hosted)\n\t--------------------\n\tdocker pushrm --provider harbor2 my-harbor-server.com/my-project/hello-world\n\n\n\n\tHow to login\n\t=============\n\n\n\tFor most registry providers docker-pushrm uses\n\tthe registry login from Docker's credentials store.\n\tFor some providers an API key needs to be specified\n\tvia env var or Docker config file.\n\n\tAlternatively credentials can be set as environment\n\tvariables. Environment variables take precedence over\n\tthe Docker credentials store.\n\n\tEnvironment variables can be specified with or without\n\ta server name. The variant without a server name takes\n\tprecedence:\n\n\t - DOCKER_USER and DOCKER_PASS\n\t - DOCKER_USER__<SERVER>_<DOMAIN> and DOCKER_PASS__<SERVER>_<DOMAIN>\n\t   (example for server 'docker.io': DOCKER_USER__DOCKER_IO=my-user\n\t   and DOCKER_PASS__DOCKER_IO=my-password)\n\n\tThe provider 'quay' needs an additional env var for the API key\n\tin form of APIKEY__<SERVERNAME>_<DOMAIN>=<apikey>.\n\n\n\tDockerhub\n\t---------\n\trun 'docker login'\n\n\t(use password or Personal Access Token (PAT) with 'admin' scope)\n\n\n\tquay\n\t----\n\t- get an api key (bearer token) from the quay webinterface\n\n\t  - option 1: env var DOCKER_APIKEY=<apikey>\n\t    or env var APIKEY__<SERVERNAME>_<DOMAIN>=<apikey>\n\t\t(example for quay.io: 'export APIKEY__QUAY_IO=myapikey')\n\n\t  - option 2: in the Docker config file (default: \"$HOME/.docker/config.json\")\n\t\tadd the json key 'plugins.docker-pushrm.apikey_<servername>' with the\n\t\tapikey as string value (example for quay.io: key name\n\t\t'plugins.docker-pushrm.apikey_quay.io')\n\n\tEnv var takes precedence.\n\n\n\tharbor\n\t------\n\trun 'docker login <servername>' (example: 'docker login demo.goharbor.io')\n\n\n\n\tCreating a README file\n\t=======================\n\n\tValid names: 'README.md' or 'README-containers.md'.\n\n\t'README-containers.md' takes precedence. This allows to set up a\n\tdifferent README file for the container registry then for the git repo.\n\n\tThe README file needs to be in the current working directory from which\n\tdocker pushrm is being called.\n\n\tIt's also possible to specify a path to a README file with\n\t'--file <path>' ('-f <path>').\n\n\n\tOptional [:TAG] argument\n\t========================\n\n\tThe [:TAG] argument is optional and has no effect for the currently\n\tsupported providers (which only support a README per repo, not per\n\ttag). It is in place in case that additional providers get added in\n\tthe future that support READMEs on the tag level.\n\n\n\tSupported environment variables\n\t===============================\n\t\n\tDOCKER_USER, DOCKER_PASS, DOCKER_APIKEY, APIKEY__<SERVER>_<DOMAIN>,\n\tPUSHRM_PROVIDER, PUSHRM_SHORT, PUSHRM_FILE, PUSHRM_DEBUG, PUSHRM_CONFIG,\n\tPUSHRM_TARGET\n\n\tCommandline parameters take precedence over environment variables.\n\tLogin environment variables take precedence over the local credentials\n\tstore.\n\n\n\n`,\n\tRunE: func(cmd *cobra.Command, args []string) error {\n\t\tif err := run(args); err != nil {\n\t\t\treturn err\n\t\t}\n\t\treturn nil\n\t},\n}\n\nfunc run(args []string) error {\n\tpushrmProvider := viper.GetString(\"provider\")\n\tpushrmFile := viper.GetString(\"file\")\n\tpushrmShortDesc := viper.GetString(\"short\")\n\n\tlog.Debug(\"subcommand \\\"pushrm\\\" called\")\n\n\t//fmt.Println(os.Getenv(\"DOCKER_CLI_PLUGIN_ORIGINAL_CLI_COMMAND\"))\n\n\t// lowest common ground: 100 runes (not bytes) on Dockerhub\n\t// this check is intentially global (not per provider) to\n\t// make cmd calls portable between providers without surprises\n\tif utf8.RuneCountInString(pushrmShortDesc) > 100 {\n\t\tlog.Error(\"Short description is too long (max 100 characters)\")\n\t\tos.Exit(1)\n\t}\n\n\t// our only positional argument: <servername>/<namespacename>/<reponame>:<tag> (servername + tag are optional)\n\ttargetinfo := os.Getenv(\"PUSHRM_TARGET\")\n\tif len(args) > 0 {\n\t\tif target := args[0]; target != \"\" {\n\t\t\ttargetinfo = target\n\t\t}\n\t}\n\n\tif targetinfo == \"\" {\n\t\treturn (errors.New(\"Missing [IMAGE] argument. Example: docker.io/mynamespace/myrepo:latest\"))\n\t\t//log.Error(\"Missing [IMAGE] argument. Example: docker.io/mynamespace/myrepo:latest\")\n\t\t//os.Exit(1)\n\t}\n\n\t// fail if namespacename is missing\n\tif len(strings.Split(targetinfo, \"/\")) < 2 {\n\t\tlog.Error(\"Invalid [IMAGE] argument - missing namespace. Example: docker.io/mynamespace/myrepo:latest\")\n\t\tos.Exit(1)\n\t}\n\t// fill up default servername, if missing\n\tif len(strings.Split(targetinfo, \"/\")) < 3 {\n\t\ttargetinfo = \"docker.io/\" + targetinfo\n\t}\n\t// fill up default tagname, if missing\n\tif strings.Contains(targetinfo, \":\") != true {\n\t\ttargetinfo = targetinfo + \":latest\"\n\t}\n\tlog.Debug(\"Using target: \", targetinfo)\n\n\tvar erro error\n\n\tif pushrmFile == \"\" {\n\t\tpushrmFile, erro = util.FindReadmeFile()\n\t\tif erro != nil {\n\t\t\tlog.Error(erro)\n\t\t\tos.Exit(1)\n\t\t}\n\t}\n\n\tlog.Debug(\"using README file: \" + pushrmFile)\n\n\treadme, erro := util.ReadFile(pushrmFile)\n\tif erro != nil {\n\t\tlog.Error(erro)\n\t\tos.Exit(1)\n\t}\n\n\tif (len(strings.Split(targetinfo, \"/\")) != 3) || (len(strings.Split(strings.Split(targetinfo, \"/\")[2], \":\")) != 2) {\n\t\tlog.Error(\"Invalid [IMAGE] argument - too many separators. Example: docker.io/mynamespace/myrepo:latest\")\n\t\tos.Exit(1)\n\t}\n\n\tservername := strings.ToLower(strings.Split(targetinfo, \"/\")[0])\n\tnamespacename := strings.Split(targetinfo, \"/\")[1]\n\treponame := strings.Split(strings.Split(targetinfo, \"/\")[2], \":\")[0]\n\ttagname := strings.Split(strings.Split(targetinfo, \"/\")[2], \":\")[1]\n\tif servername == \"docker.io\" {\n\t\tpushrmProvider = \"dockerhub\"\n\t}\n\tif servername == \"quay.io\" {\n\t\tpushrmProvider = \"quay\"\n\t}\n\tlog.Debug(\"server: \", servername)\n\tlog.Debug(\"namespace: \", namespacename)\n\tlog.Debug(\"repo: \", reponame)\n\tlog.Debug(\"tag: \", tagname)\n\tlog.Debug(\"repo provider: \", pushrmProvider)\n\n\tfor _, e := range []string{namespacename, reponame, tagname, servername} {\n\t\t// yes, dots are allowed in all these fields\n\t\tif regexp.MustCompile(`^[0-9a-zA-Z\\-_.]+$`).MatchString(e) == false {\n\t\t\tlog.Error(\"Invalid [IMAGE argument] - bad characters or empty value. Example: docker.io/mynamespace/myrepo:latest\")\n\t\t\tos.Exit(1)\n\t\t}\n\t}\n\n\tif pushrmProvider == \"dockerhub\" && servername != \"docker.io\" {\n\t\tlog.Error(\"servername \", servername, \" is not valid for provider \", pushrmProvider, \" (try \\\"docker.io\\\")\")\n\t\tos.Exit(1)\n\t}\n\n\tvar prov provider.Provider\n\n\tswitch pushrmProvider {\n\tcase \"dockerhub\":\n\t\tprov = dockerhub.Dockerhub{}\n\tcase \"quay\":\n\t\tprov = quay.Quay{}\n\tcase \"harbor2\":\n\t\tprov = harbor2.Harbor2{}\n\tdefault:\n\t\tlog.Error(\"unsupported repo provider: \", pushrmProvider+\". See \\\"--help\\\" for supported providers. \")\n\t\tos.Exit(1)\n\t}\n\n\tauthident := prov.GetAuthident()\n\tvar authidentIsFuzzy bool\n\tauthidentIsFuzzy = false\n\n\tif authident == \"__SERVERNAME__\" {\n\t\tauthident = servername\n\t\tauthidentIsFuzzy = true\n\t}\n\n\tvar dockerUser string\n\tvar dockerPasswd string\n\tvar err error\n\n\t// generic env var (no servername specified) takes precedence\n\tdockerUser = os.Getenv(\"DOCKER_USER\")\n\tdockerPasswd = os.Getenv(\"DOCKER_PASS\")\n\tif dockerUser != \"\" && dockerPasswd != \"\" {\n\t\tlog.Debug(\"using credentials for user \" + dockerUser + \" from generic env var\")\n\t}\n\n\t// env var with servername is next\n\tif dockerUser == \"\" || dockerPasswd == \"\" {\n\t\tsuffix := strings.ToUpper(strings.Replace(servername, \".\", \"_\", -1))\n\t\tdockerUser = os.Getenv(\"DOCKER_USER__\" + suffix)\n\t\tdockerPasswd = os.Getenv(\"DOCKER_PASS__\" + suffix)\n\t\tif dockerUser != \"\" && dockerPasswd != \"\" {\n\t\t\tlog.Debug(\"using credentials for user \" + dockerUser + \" from env var for suffix \" + suffix)\n\t\t}\n\t}\n\n\t// if credentials are not found in env vars, look in the Docker credentials store\n\tif (dockerUser == \"\" || dockerPasswd == \"\") && authident != \"__NONE__\" {\n\t\tlog.Debug(\"no credentials found in env vars. Trying Docker credentials store\")\n\t\tlog.Debug(\"Using config file: \", viper.ConfigFileUsed())\n\n\t\tif viper.ConfigFileUsed() == \"\" {\n\t\t\tlog.Error(\"Docker config file not found. Run \\\"docker login\\\" first to create it. \")\n\t\t\tos.Exit(1)\n\t\t}\n\n\t\t// a provider can request to handle auth itself with authident __NONE__\n\t\tif authident != \"__NONE__\" {\n\t\t\tdockerUser, dockerPasswd, err = util.GetDockerCreds(authident, authidentIsFuzzy)\n\t\t\tif err != nil {\n\t\t\t\tlog.Error(err)\n\t\t\t\tos.Exit(1)\n\t\t\t}\n\t\t} else {\n\t\t\tdockerUser = \"\"\n\t\t\tdockerPasswd = \"\"\n\t\t}\n\t}\n\n\t//log.Debug(\"Using Docker creds: \", dockerUser, \" \", dockerPasswd)\n\tlog.Debug(\"Using Docker creds: \", dockerUser, \" \", \"********\")\n\n\terr = prov.Pushrm(servername, namespacename, reponame, tagname, dockerUser, dockerPasswd, readme, pushrmShortDesc)\n\tif err != nil {\n\t\tlog.Error(err)\n\t\tos.Exit(1)\n\t}\n\n\treturn nil\n\n\t// ---------\n}\n\nfunc init() {\n\n\tconst usageTemplate = `\nUsage:{{if .Runnable}}\n  {{.UseLine}}{{end}}{{if .HasAvailableSubCommands}}\n  {{.CommandPath}} [command]{{end}}\n\nFlags:\n{{.LocalFlags.FlagUsages | trimTrailingWhitespaces}}{{if .HasAvailableInheritedFlags}}\n\nGlobal Flags:\n{{.InheritedFlags.FlagUsages | trimTrailingWhitespaces}}{{end}}\n  `\n\n\tconst helpTemplate = `\n{{with (or .Long .Short)}}{{. | trimTrailingWhitespaces}}\n{{end}}{{if or .Runnable .HasSubCommands}}{{.UsageString}}{{end}}\n  `\n\n\trootCmd.AddCommand(pushrmCmd)\n\t// Here you will define your flags and configuration settings.\n\n\t// Cobra supports Persistent Flags which will work for this command\n\t// and all subcommands, e.g.:\n\t// pushrmCmd.PersistentFlags().String(\"foo\", \"\", \"A help for foo\")\n\n\t// Cobra supports local flags which will only run when this command\n\t// is called directly, e.g.:\n\t// pushrmCmd.Flags().BoolP(\"toggle\", \"t\", false, \"Help message for toggle\")\n\tpushrmCmd.Flags().StringVarP(&providername, \"provider\", \"p\", \"dockerhub\", \"repo type: dockerhub, harbor2, quay\")\n\tpushrmCmd.Flags().StringVarP(&rfile, \"file\", \"f\", \"\", \"README file (defaults: \\\"./README-containers.md\\\", \\\"./README.md\\\")\")\n\tpushrmCmd.Flags().StringVarP(&shortdesc, \"short\", \"s\", \"\", \"short description (optional)\")\n\tpushrmCmd.Parent().SetUsageTemplate(usageTemplate)\n\tpushrmCmd.Parent().SetHelpTemplate(helpTemplate)\n\n\tviper.BindPFlag(\"provider\", pushrmCmd.Flags().Lookup(\"provider\"))\n\tviper.BindPFlag(\"file\", pushrmCmd.Flags().Lookup(\"file\"))\n\tviper.BindPFlag(\"short\", pushrmCmd.Flags().Lookup(\"short\"))\n}\n"
  },
  {
    "path": "cmd/root.go",
    "content": "/*\nCopyright © 2020 Christian Korneck <christian@korneck.de>\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n*/\n\npackage cmd\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\t\"path/filepath\"\n\n\tlog \"github.com/sirupsen/logrus\"\n\n\t\"github.com/spf13/cobra\"\n\n\thomedir \"github.com/mitchellh/go-homedir\"\n\t\"github.com/spf13/viper\"\n)\n\nvar cfgFile string\nvar isDebug bool\n\nvar dockerGlobalConfig string\nvar dockerGlobalContext string\nvar dockerGlobalHost string\nvar dockerGlobalTlscacert string\nvar dockerGlobalLoglevel string\nvar dockerGlobalTlscert string\nvar dockerGlobalTlskey string\n\n// rootCmd represents the base command when called without any subcommands\nvar rootCmd = &cobra.Command{\n\tUse:   \"docker-pushrm\",\n\tShort: \"push README file from current working directory to container registry (Dockerhub, quay, harbor2)\",\n\tLong: `push README file from current working directory to container registry (Dockerhub, quay, harbor2)\n`,\n\t// Uncomment the following line if your bare application\n\t// has an action associated with it:\n\t//\tRun: func(cmd *cobra.Command, args []string) { },\n}\n\n// Execute adds all child commands to the root command and sets flags appropriately.\n// This is called by main.main(). It only needs to happen once to the rootCmd.\nfunc Execute() {\n\tif err := rootCmd.Execute(); err != nil {\n\t\t//at this point we don't have logrus yet, using print instead\n\t\tfmt.Println(err)\n\t\tos.Exit(1)\n\t}\n}\n\nfunc init() {\n\n\tcobra.OnInitialize(initConfig)\n\n\t// Here you will define your flags and configuration settings.\n\t// Cobra supports persistent flags, which, if defined here,\n\t// will be global for your application.\n\n\trootCmd.PersistentFlags().StringVar(&cfgFile, \"config\", \"\", \"config file (default \\\"$HOME/.docker/config.json\\\")\")\n\trootCmd.PersistentFlags().BoolVarP(&isDebug, \"debug\", \"D\", false, \"Enable debug mode\")\n\n\t// these are the docker cli global flags\n\t// (we define them here so that our plugin doesn't break if they're set, but don't do anything with em)\n\trootCmd.PersistentFlags().StringVarP(&dockerGlobalContext, \"context\", \"c\", \"\", \"(not supported)\")\n\trootCmd.PersistentFlags().StringVarP(&dockerGlobalHost, \"host\", \"H\", \"\", \"(not supported)\")\n\trootCmd.PersistentFlags().StringVarP(&dockerGlobalLoglevel, \"log-level\", \"l\", \"\", \"(not supported)\")\n\trootCmd.PersistentFlags().Bool(\"tls\", true, \"(not supported)\")\n\trootCmd.PersistentFlags().Bool(\"tlsverify\", true, \"(not supported)\")\n\trootCmd.PersistentFlags().StringVar(&dockerGlobalTlscacert, \"tlscacert\", \"\", \"(not supported)\")\n\trootCmd.PersistentFlags().StringVar(&dockerGlobalTlscert, \"tlscert\", \"\", \"(not supported)\")\n\trootCmd.PersistentFlags().StringVar(&dockerGlobalTlskey, \"tlskey\", \"\", \"(not supported)\")\n\n\t// hide unsupported flags so that they don't show up with `docker-pushrm pushrm --help`\n\trootCmd.PersistentFlags().MarkHidden(\"context\")\n\trootCmd.PersistentFlags().MarkHidden(\"host\")\n\trootCmd.PersistentFlags().MarkHidden(\"log-level\")\n\trootCmd.PersistentFlags().MarkHidden(\"tls\")\n\trootCmd.PersistentFlags().MarkHidden(\"tlsverify\")\n\trootCmd.PersistentFlags().MarkHidden(\"tlscacert\")\n\trootCmd.PersistentFlags().MarkHidden(\"tlscert\")\n\trootCmd.PersistentFlags().MarkHidden(\"tlskey\")\n\n\tviper.BindPFlag(\"config\", rootCmd.PersistentFlags().Lookup(\"config\"))\n\tviper.BindPFlag(\"debug\", rootCmd.PersistentFlags().Lookup(\"debug\"))\n\n\t// Cobra also supports local flags, which will only run\n\t// when this action is called directly.\n\t// rootCmd.Flags().BoolP(\"toggle\", \"t\", false, \"Help message for toggle\")\n\n}\n\n// initConfig reads in config file and ENV variables if set.\nfunc initConfig() {\n\tviper.AutomaticEnv() // read in environment variables that match\n\tviper.SetEnvPrefix(\"pushrm\")\n\n\tpushrmConfig := viper.GetString(\"config\")\n\tpushrmDebug := viper.GetBool(\"debug\")\n\n\tif pushrmDebug {\n\t\tlog.SetLevel(log.DebugLevel)\n\t} else {\n\t\tlog.SetLevel(log.WarnLevel)\n\t}\n\tlog.SetFormatter(&log.TextFormatter{DisableTimestamp: true})\n\n\tlog.Debug(\"root cmd init config\")\n\n\tif pushrmConfig != \"\" {\n\t\t// Use config file from the flag.\n\t\tviper.SetConfigFile(pushrmConfig)\n\t} else {\n\t\t// Find home directory.\n\t\thome, err := homedir.Dir()\n\t\tif err != nil {\n\t\t\tlog.Debug(err)\n\t\t\tlog.Error(\"can't find home dir / Docker config file\")\n\t\t\tos.Exit(1)\n\t\t}\n\t\tlog.Debug(\"home dir: \", home)\n\n\t\t// Search config in home directory with name \".docker-pushrm\" (without extension).\n\t\tviper.AddConfigPath(filepath.Join(home, \"/.docker\"))\n\n\t\tviper.SetConfigName(\"config\") //filename without .json extension\n\t}\n\n\t// If a config file is found, read it in.\n\tif err := viper.ReadInConfig(); err == nil {\n\t}\n\n}\n"
  },
  {
    "path": "go.mod",
    "content": "module github.com/christian-korneck/docker-pushrm\n\ngo 1.16\n\nrequire (\n\tgithub.com/mitchellh/go-homedir v1.1.0\n\tgithub.com/sirupsen/logrus v1.8.1\n\tgithub.com/spf13/cobra v1.2.1\n\tgithub.com/spf13/viper v1.8.1\n\tgolang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c // indirect\n\tgolang.org/x/text v0.3.6 // indirect\n)\n"
  },
  {
    "path": "go.sum",
    "content": "cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=\ncloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=\ncloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=\ncloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=\ncloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=\ncloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=\ncloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=\ncloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To=\ncloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4=\ncloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M=\ncloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc=\ncloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk=\ncloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs=\ncloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc=\ncloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY=\ncloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI=\ncloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk=\ncloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg=\ncloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8=\ncloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0=\ncloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=\ncloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=\ncloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=\ncloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg=\ncloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc=\ncloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ=\ncloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=\ncloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk=\ncloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk=\ncloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=\ncloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=\ncloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA=\ncloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU=\ncloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=\ncloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos=\ncloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk=\ncloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=\ncloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=\ndmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=\ngithub.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=\ngithub.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=\ngithub.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=\ngithub.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=\ngithub.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=\ngithub.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=\ngithub.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=\ngithub.com/bketelsen/crypt v0.0.4/go.mod h1:aI6NrJ0pMGgvZKL1iVgXLnfIFJtfV+bKCoqOes/6LfM=\ngithub.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=\ngithub.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=\ngithub.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=\ngithub.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=\ngithub.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=\ngithub.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=\ngithub.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=\ngithub.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=\ngithub.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=\ngithub.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=\ngithub.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=\ngithub.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=\ngithub.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=\ngithub.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=\ngithub.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=\ngithub.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=\ngithub.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=\ngithub.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po=\ngithub.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=\ngithub.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=\ngithub.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=\ngithub.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=\ngithub.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=\ngithub.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=\ngithub.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=\ngithub.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=\ngithub.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=\ngithub.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=\ngithub.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=\ngithub.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=\ngithub.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=\ngithub.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=\ngithub.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=\ngithub.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=\ngithub.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=\ngithub.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=\ngithub.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=\ngithub.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=\ngithub.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=\ngithub.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=\ngithub.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=\ngithub.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8=\ngithub.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=\ngithub.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=\ngithub.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=\ngithub.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=\ngithub.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=\ngithub.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk=\ngithub.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=\ngithub.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=\ngithub.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=\ngithub.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=\ngithub.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=\ngithub.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=\ngithub.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=\ngithub.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=\ngithub.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=\ngithub.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM=\ngithub.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=\ngithub.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=\ngithub.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=\ngithub.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=\ngithub.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=\ngithub.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=\ngithub.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=\ngithub.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=\ngithub.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=\ngithub.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=\ngithub.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=\ngithub.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=\ngithub.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=\ngithub.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=\ngithub.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=\ngithub.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=\ngithub.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=\ngithub.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=\ngithub.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=\ngithub.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=\ngithub.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=\ngithub.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=\ngithub.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=\ngithub.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=\ngithub.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=\ngithub.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=\ngithub.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=\ngithub.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=\ngithub.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=\ngithub.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=\ngithub.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=\ngithub.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=\ngithub.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=\ngithub.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8=\ngithub.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=\ngithub.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=\ngithub.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q=\ngithub.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=\ngithub.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=\ngithub.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=\ngithub.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=\ngithub.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=\ngithub.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=\ngithub.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU=\ngithub.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU=\ngithub.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=\ngithub.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=\ngithub.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=\ngithub.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90=\ngithub.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=\ngithub.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=\ngithub.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=\ngithub.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=\ngithub.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=\ngithub.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ=\ngithub.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I=\ngithub.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=\ngithub.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=\ngithub.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=\ngithub.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=\ngithub.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=\ngithub.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=\ngithub.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=\ngithub.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=\ngithub.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=\ngithub.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=\ngithub.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=\ngithub.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=\ngithub.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=\ngithub.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=\ngithub.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=\ngithub.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=\ngithub.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=\ngithub.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=\ngithub.com/magiconair/properties v1.8.5 h1:b6kJs+EmPFMYGkow9GiUyCyOvIwYetYJ3fSaWak/Gls=\ngithub.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60=\ngithub.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=\ngithub.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=\ngithub.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=\ngithub.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=\ngithub.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=\ngithub.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=\ngithub.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=\ngithub.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=\ngithub.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg=\ngithub.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY=\ngithub.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=\ngithub.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=\ngithub.com/mitchellh/mapstructure v1.4.1 h1:CpVNEelQCZBooIPDn+AR3NpivK/TIKU8bDxdASFVQag=\ngithub.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=\ngithub.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=\ngithub.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=\ngithub.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=\ngithub.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=\ngithub.com/pelletier/go-toml v1.9.3 h1:zeC5b1GviRUyKYd6OJPvBU/mcVDVoL1OhT17FCt5dSQ=\ngithub.com/pelletier/go-toml v1.9.3/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=\ngithub.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=\ngithub.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI=\ngithub.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=\ngithub.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=\ngithub.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=\ngithub.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=\ngithub.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=\ngithub.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=\ngithub.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=\ngithub.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=\ngithub.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=\ngithub.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=\ngithub.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE=\ngithub.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=\ngithub.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM=\ngithub.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=\ngithub.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s=\ngithub.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=\ngithub.com/spf13/afero v1.6.0 h1:xoax2sJ2DT8S8xA2paPFjDCScCNeWsg75VG0DLRreiY=\ngithub.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I=\ngithub.com/spf13/cast v1.3.1 h1:nFm6S0SMdyzrzcmThSipiEubIDy8WEXKNZ0UOgiRpng=\ngithub.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=\ngithub.com/spf13/cobra v1.2.1 h1:+KmjbUw1hriSNMF55oPrkZcb27aECyrj8V2ytv7kWDw=\ngithub.com/spf13/cobra v1.2.1/go.mod h1:ExllRjgxM/piMAM+3tAZvg8fsklGAf3tPfi+i8t68Nk=\ngithub.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk=\ngithub.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo=\ngithub.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=\ngithub.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=\ngithub.com/spf13/viper v1.8.1 h1:Kq1fyeebqsBfbjZj4EL7gj2IO0mMaiyjYUWcUsl2O44=\ngithub.com/spf13/viper v1.8.1/go.mod h1:o0Pch8wJ9BVSWGQMbra6iw0oQ5oktSIBaujf1rJH9Ns=\ngithub.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=\ngithub.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=\ngithub.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=\ngithub.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=\ngithub.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=\ngithub.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=\ngithub.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=\ngithub.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=\ngithub.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s=\ngithub.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=\ngithub.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=\ngithub.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=\ngithub.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=\ngithub.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=\ngithub.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=\ngo.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs=\ngo.etcd.io/etcd/client/pkg/v3 v3.5.0/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g=\ngo.etcd.io/etcd/client/v2 v2.305.0/go.mod h1:h9puh54ZTgAKtEbut2oe9P4L/oqKCVB6xsXlzd7alYQ=\ngo.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=\ngo.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=\ngo.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=\ngo.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=\ngo.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=\ngo.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk=\ngo.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E=\ngo.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=\ngo.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=\ngo.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo=\ngolang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=\ngolang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=\ngolang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=\ngolang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=\ngolang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=\ngolang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=\ngolang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=\ngolang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=\ngolang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=\ngolang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=\ngolang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=\ngolang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=\ngolang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=\ngolang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=\ngolang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=\ngolang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=\ngolang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=\ngolang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=\ngolang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=\ngolang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=\ngolang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=\ngolang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=\ngolang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=\ngolang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=\ngolang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=\ngolang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=\ngolang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=\ngolang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=\ngolang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=\ngolang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=\ngolang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=\ngolang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=\ngolang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=\ngolang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=\ngolang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=\ngolang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=\ngolang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=\ngolang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=\ngolang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=\ngolang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=\ngolang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=\ngolang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=\ngolang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\ngolang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\ngolang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\ngolang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\ngolang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\ngolang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\ngolang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=\ngolang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=\ngolang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=\ngolang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=\ngolang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=\ngolang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=\ngolang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=\ngolang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=\ngolang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=\ngolang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=\ngolang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=\ngolang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=\ngolang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=\ngolang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=\ngolang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=\ngolang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=\ngolang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=\ngolang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=\ngolang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=\ngolang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc=\ngolang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=\ngolang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=\ngolang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=\ngolang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=\ngolang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=\ngolang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=\ngolang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=\ngolang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=\ngolang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=\ngolang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=\ngolang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=\ngolang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=\ngolang.org/x/oauth2 v0.0.0-20210402161424-2e8d93401602/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=\ngolang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c h1:F1jZWGFhYfh0Ci55sIpILtKKK8p3i2/krTr0H1rg74I=\ngolang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=\ngolang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=\ngolang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=\ngolang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=\ngolang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=\ngolang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=\ngolang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=\ngolang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=\ngolang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=\ngolang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M=\ngolang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=\ngolang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=\ngolang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=\ngolang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=\ngolang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=\ngolang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=\ngolang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=\ngolang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=\ngolang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=\ngolang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=\ngolang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=\ngolang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=\ngolang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=\ngolang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=\ngolang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=\ngolang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=\ngolang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=\ngolang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=\ngolang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=\ngolang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=\ngolang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=\ngolang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=\ngolang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=\ngolang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=\ngolang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=\ngolang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=\ngolang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=\ngolang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=\ngolang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=\ngolang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=\ngolang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=\ngolang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=\ngolang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=\ngolang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=\ngolang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=\ngolang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=\ngolang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=\ngolang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=\ngolang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE=\ngolang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=\ngolang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=\ngolang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=\ngolang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=\ngolang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=\ngolang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=\ngolang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=\ngolang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=\ngolang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=\ngolang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=\ngolang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=\ngoogle.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=\ngoogle.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=\ngoogle.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=\ngoogle.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=\ngoogle.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=\ngoogle.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=\ngoogle.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=\ngoogle.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=\ngoogle.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=\ngoogle.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=\ngoogle.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=\ngoogle.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=\ngoogle.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=\ngoogle.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=\ngoogle.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM=\ngoogle.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc=\ngoogle.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg=\ngoogle.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE=\ngoogle.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8=\ngoogle.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU=\ngoogle.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94=\ngoogle.golang.org/api v0.44.0/go.mod h1:EBOGZqzyhtvMDoxwS97ctnh0zUmYY6CxqXsc1AvkYD8=\ngoogle.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=\ngoogle.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=\ngoogle.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=\ngoogle.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=\ngoogle.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=\ngoogle.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=\ngoogle.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=\ngoogle.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=\ngoogle.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=\ngoogle.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=\ngoogle.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=\ngoogle.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=\ngoogle.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=\ngoogle.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=\ngoogle.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=\ngoogle.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=\ngoogle.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=\ngoogle.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=\ngoogle.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=\ngoogle.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=\ngoogle.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=\ngoogle.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA=\ngoogle.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=\ngoogle.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=\ngoogle.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=\ngoogle.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=\ngoogle.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=\ngoogle.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=\ngoogle.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=\ngoogle.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=\ngoogle.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=\ngoogle.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U=\ngoogle.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=\ngoogle.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA=\ngoogle.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=\ngoogle.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=\ngoogle.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=\ngoogle.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=\ngoogle.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=\ngoogle.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=\ngoogle.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=\ngoogle.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=\ngoogle.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=\ngoogle.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=\ngoogle.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=\ngoogle.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=\ngoogle.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A=\ngoogle.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0=\ngoogle.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=\ngoogle.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=\ngoogle.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=\ngoogle.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=\ngoogle.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=\ngoogle.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=\ngoogle.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=\ngoogle.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=\ngoogle.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60=\ngoogle.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=\ngoogle.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=\ngoogle.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=\ngoogle.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=\ngoogle.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=\ngoogle.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=\ngoogle.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8=\ngoogle.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=\ngoogle.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=\ngoogle.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=\ngoogle.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=\ngoogle.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=\ngoogle.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=\ngoogle.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=\ngoogle.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=\ngoogle.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=\ngoogle.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=\ngoogle.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=\ngoogle.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=\ngoogle.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=\ngoogle.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=\ngoogle.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=\ngoogle.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=\ngopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=\ngopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=\ngopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=\ngopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=\ngopkg.in/ini.v1 v1.62.0 h1:duBzk771uxoUuOlyRLkHsygud9+5lrlGjdFBb4mSKDU=\ngopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=\ngopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\ngopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\ngopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\ngopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=\ngopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=\ngopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=\ngopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=\ngopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=\nhonnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=\nhonnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=\nhonnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=\nhonnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=\nhonnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=\nhonnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=\nhonnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=\nrsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=\nrsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=\nrsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=\n"
  },
  {
    "path": "gon.json",
    "content": "{\n    \"source\" : [\"./docker-pushrm\"],\n    \"bundle_id\" : \"de.korneck.christian.docker-pushrm\",\n    \"apple_id\": {\n        \"password\":  \"@env:AC_PASSWORD\"\n    },\n    \"sign\" :{\n        \"application_identity\" : \"Developer ID Application: Christian Korneck\"\n    },\n    \"zip\" :{\n        \"output_path\" : \"./docker-pushrm.zip\"\n    }\n}"
  },
  {
    "path": "main.go",
    "content": "/*\nCopyright © 2020 Christian Korneck <christian@korneck.de>\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n*/\n\npackage main\n\nimport (\n\t\"os\"\n\n\t\"github.com/christian-korneck/docker-pushrm/cmd\"\n\t\"github.com/christian-korneck/docker-pushrm/util\"\n)\n\nfunc main() {\n\n\t// if called as a standalone tool (not as a docker cli plugin), proxy directly to the `pushrm` subcommand\n\tif (os.Getenv(\"DOCKER_CLI_PLUGIN_ORIGINAL_CLI_COMMAND\") == \"\") && (util.StringInSlice(\"docker-cli-plugin-metadata\", os.Args) == false) {\n\n\t\tnewArgs := make([]string, (len(os.Args) + 1))\n\n\t\tnewArgs[0] = os.Args[0]\n\t\tnewArgs[1] = \"pushrm\"\n\t\tfor i := 2; i <= len(os.Args); i++ {\n\t\t\tnewArgs[i] = os.Args[i-1]\n\t\t}\n\t\tos.Args = newArgs\n\n\t}\n\n\t// Cobra, übernehmen Sie\n\tcmd.Execute()\n}\n"
  },
  {
    "path": "provider/dockerhub/dockerhub.go",
    "content": "/*\nCopyright © 2020 Christian Korneck <christian@korneck.de>\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n*/\n\npackage dockerhub\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"io/ioutil\"\n\t\"net/http\"\n\t\"strings\"\n\n\t\"github.com/christian-korneck/docker-pushrm/util\"\n\tlog \"github.com/sirupsen/logrus\"\n)\n\n//Dockerhub struct\ntype Dockerhub struct {\n}\n\n//Pushrm is the main provider function\nfunc (f Dockerhub) Pushrm(servername string, namespacename string, reponame string, tagname string, dockerUser string, dockerPasswd string, readme string, shortdesc string) error {\n\n\tlog.Debug(\"Dockerhub.Pushrm called\")\n\tjwt, err := GetJwt(dockerUser, dockerPasswd)\n\tif err != nil {\n\t\tlog.Debug(err)\n\t\treturn fmt.Errorf(\"error trying to get a JWT token from Dockerhub for the stored Docker login. Try \\\"docker logout\\\" and \\\"docker login\\\". Also, if you have 2FA auth enabled in Dockerhub you'll need to disable it for this tool to work. (This is an unfortunate Dockerhub limitation, see docs for more infos). \")\n\t}\n\terr = PatchDescription(jwt, readme, namespacename, reponame, shortdesc)\n\tif err != nil {\n\t\tlog.Debug(err)\n\t\treturn fmt.Errorf(\"error pushing readme to repo server. See error message below. Run with \\\"--debug\\\" for more details. \\n\\n\" + err.Error())\n\t}\n\n\treturn nil\n}\n\n//GetAuthident returns authident for local Docker credentials store\nfunc (f Dockerhub) GetAuthident() (authident string) {\n\tlog.Debug(\"Dockerhub.GetAuthident called\")\n\tauthident = \"https://index.docker.io/v1/\"\n\treturn\n}\n\n//GetJwt Auth against Dockerhub with user/passwd and request a jwt token\nfunc GetJwt(dockerUser string, dockerPasswd string) (jwt string, error error) {\n\n\turl := \"https://hub.docker.com/v2/users/login/\"\n\tmethod := \"POST\"\n\n\tpayloadJSON, err := json.Marshal(map[string]string{\"username\": dockerUser, \"password\": dockerPasswd})\n\tif err != nil {\n\t\tlog.Debug(err)\n\t\treturn \"\", fmt.Errorf(\"error retrieving Dockerhub jwt token, error marshal payload\")\n\t}\n\n\tpayloadStr := util.BytesToString(payloadJSON)\n\tpayload := strings.NewReader(payloadStr)\n\n\tclient := &http.Client{}\n\treq, err := http.NewRequest(method, url, payload)\n\n\tif err != nil {\n\t\tlog.Debug(err)\n\t\treturn \"\", fmt.Errorf(\"error retrieving Dockerhub jwt token, error creating http request\")\n\t}\n\treq.Header.Add(\"Content-Type\", \"application/json\")\n\n\tres, err := client.Do(req)\n\tif err != nil {\n\t\tlog.Debug(err)\n\t\treturn \"\", fmt.Errorf(\"error retrieving Dockerhub jwt token, error making http request\")\n\t}\n\n\tlog.Debug(\"retrieve Dockerhub jwt token, status code: \", res.StatusCode)\n\n\tif res.StatusCode != 200 {\n\t\treturn \"\", fmt.Errorf(\"error retrieving Dockerhub jwt token, bad status code for response: \" + res.Status)\n\n\t}\n\n\tdefer res.Body.Close()\n\tbody, err := ioutil.ReadAll(res.Body)\n\tif err != nil {\n\t\tlog.Debug(err)\n\t\treturn \"\", fmt.Errorf(\"error retrieving Dockerhub jwt token, error reading response body\")\n\t}\n\n\tvar dat map[string]interface{}\n\tif err := json.Unmarshal(body, &dat); err != nil {\n\t\tlog.Debug(err)\n\t\treturn \"\", fmt.Errorf(\"error retrieving Dockerhub jwt token, error parsing json\")\n\t}\n\n\tif dat[\"token\"] == nil || dat[\"token\"].(string) == \"\" {\n\t\treturn \"\", fmt.Errorf(\"error retrieving Dockerhub jwt token, no jtw token received\")\n\t}\n\n\treturn dat[\"token\"].(string), nil\n}\n\n//PatchDescription - api call to update the repo description\nfunc PatchDescription(jwt string, readme string, namespacename string, reponame string, shortdesc string) (error error) {\n\n\t// trailing slash is crucial\n\tapiurl := \"https://hub.docker.com/v2/repositories/\" + namespacename + \"/\" + reponame + \"/\"\n\tmethod := \"PATCH\"\n\n\tbodydata := make(map[string]string)\n\tbodydata[\"full_description\"] = readme\n\tif shortdesc != \"\" {\n\t\tbodydata[\"description\"] = shortdesc\n\t}\n\tjsonbody, _ := json.Marshal(bodydata)\n\n\tpayload := strings.NewReader(string(jsonbody))\n\tclient := &http.Client{}\n\treq, err := http.NewRequest(method, apiurl, payload)\n\tif err != nil {\n\t\tlog.Debug(err)\n\t\treturn fmt.Errorf(\"error pushing README, error creating http request\")\n\t}\n\n\treq.Header.Add(\"Authorization\", \"JWT \"+jwt)\n\treq.Header.Add(\"Content-Type\", \"application/json\")\n\n\tres, err := client.Do(req)\n\tif err != nil {\n\t\tlog.Debug(err)\n\t\treturn fmt.Errorf(\"error pushing README, error creating http request\")\n\t}\n\n\tdefer res.Body.Close()\n\tbody, err := ioutil.ReadAll(res.Body)\n\tif err != nil {\n\t\tlog.Debug(err)\n\t\treturn fmt.Errorf(\"error pushing README, error reading response body\")\n\t}\n\n\tlog.Debug(\"push readme, response body: \", string(body))\n\n\tvar dat map[string]interface{}\n\tif err := json.Unmarshal(body, &dat); err != nil {\n\t\tlog.Debug(err)\n\t\treturn fmt.Errorf(\"error pushing README, error parsing returned json\")\n\t}\n\n\tlog.Debug(\"push README, status code: \", res.StatusCode)\n\n\tif res.StatusCode != 200 {\n\t\tmsg := \"error pushing README, bad status code for response: \" + res.Status\n\t\tif dat[\"detail\"] != nil {\n\t\t\tmsg = msg + \". Server responded: \\\"\" + dat[\"detail\"].(string) + \"\\\"\"\n\t\t}\n\t\tif res.StatusCode == 403 {\n\t\t\tmsg = msg + \". Try \\\"docker logout\\\" and \\\"docker login\\\". If you use a PAT token make sure it has sufficient privileges (\\\"admin\\\" scope).\"\n\n\t\t}\n\t\treturn fmt.Errorf(msg)\n\n\t}\n\n\tif dat[\"full_description\"] != readme {\n\t\treturn fmt.Errorf(\"error pushing README, pushed readme to repo server but validation failed\")\n\t}\n\n\tif shortdesc != \"\" && dat[\"description\"] != shortdesc {\n\t\treturn fmt.Errorf(\"error setting Short Description, pushed to repo server but validation failed\")\n\t}\n\n\tlog.Debug(\"content validation successfull, readme successfully pushed to repo server\")\n\treturn nil\n\n}\n"
  },
  {
    "path": "provider/harbor2/harbor2.go",
    "content": "/*\nCopyright © 2020 Christian Korneck <christian@korneck.de>\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n*/\n\npackage harbor2\n\nimport (\n\t\"encoding/base64\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"io/ioutil\"\n\t\"net/http\"\n\t\"strings\"\n\n\tlog \"github.com/sirupsen/logrus\"\n)\n\n//Harbor2 struct\ntype Harbor2 struct {\n}\n\n//Pushrm is the main provider function\nfunc (f Harbor2) Pushrm(servername string, namespacename string, reponame string, tagname string, dockerUser string, dockerPasswd string, readme string, shortdesc string) error {\n\n\tif shortdesc != \"\" {\n\t\tlog.Warn(\"Short description not supported for provider \\\"harbor2\\\". Ignoring.\")\n\t}\n\n\tlog.Debug(\"Harbor2.Pushrm called\")\n\n\terr := PatchDescription(dockerUser, dockerPasswd, readme, servername, namespacename, reponame)\n\tif err != nil {\n\t\tlog.Debug(err)\n\t\treturn fmt.Errorf(\"error pushing readme to repo server. See error message below. Run with \\\"--debug\\\" for more details. \\n\\n\" + err.Error())\n\t}\n\n\treturn nil\n}\n\n//GetAuthident returns authident for local Docker credentials store\nfunc (f Harbor2) GetAuthident() (authident string) {\n\tlog.Debug(\"Harbor2.GetAuthident called\")\n\tauthident = \"__SERVERNAME__\"\n\treturn\n}\n\n//PatchDescription - api call to update the repo description\nfunc PatchDescription(dockerUser string, dockerPasswd string, readme string, servername string, namespacename string, reponame string) (error error) {\n\n\tapiurl := \"https://\" + servername + \"/api/v2.0/projects/\" + namespacename + \"/repositories/\" + reponame\n\tmethod := \"PUT\"\n\n\tjsonbody, _ := json.Marshal(map[string]string{\"description\": readme})\n\tpayload := strings.NewReader(string(jsonbody))\n\n\tclient := &http.Client{}\n\treq, err := http.NewRequest(method, apiurl, payload)\n\tif err != nil {\n\t\tlog.Debug(err)\n\t\treturn fmt.Errorf(\"error pushing README, error creating http request\")\n\t}\n\n\tcreds := base64.StdEncoding.EncodeToString([]byte(dockerUser + \":\" + dockerPasswd))\n\treq.Header.Add(\"Authorization\", \"Basic \"+creds)\n\treq.Header.Add(\"Content-Type\", \"application/json\")\n\n\tres, err := client.Do(req)\n\tif err != nil {\n\t\tlog.Debug(err)\n\t\treturn fmt.Errorf(\"error pushing README, error creating http request\")\n\t}\n\n\tdefer res.Body.Close()\n\tbody, err := ioutil.ReadAll(res.Body)\n\tif err != nil {\n\t\tlog.Debug(err)\n\t\treturn fmt.Errorf(\"error pushing README, error reading response body\")\n\t}\n\n\tlog.Debug(\"push readme, response body: \" + string(body))\n\n\tvar dat map[string]interface{}\n\t// json only returned in case of failure for error message, otherwise empty\n\tif res.StatusCode != 200 {\n\t\tif err := json.Unmarshal(body, &dat); err != nil {\n\t\t\tlog.Debug(err)\n\t\t}\n\t}\n\n\tlog.Debug(\"push README, status code: \", res.StatusCode)\n\n\tif res.StatusCode != 200 {\n\t\tmsg := \"error pushing README, bad status code for response: \" + res.Status\n\t\tif dat[\"errors\"] != nil {\n\n\t\t\tfirsterror := dat[\"errors\"].([]interface{})[0].(map[string]interface{})\n\t\t\tmsg = msg + \". Server responded: \\\"\" + firsterror[\"code\"].(string) + \" - \" + firsterror[\"message\"].(string) + \"\\\"\"\n\t\t}\n\t\tif res.StatusCode == 403 {\n\t\t\tmsg = msg + \". Try \\\"docker logout\\\" and \\\"docker login\\\". \"\n\n\t\t}\n\t\treturn fmt.Errorf(msg)\n\n\t} else {\n\t\tlog.Debug(\"status code OK, readme successfully pushed to repo server\")\n\t\treturn nil\n\t}\n\n}\n"
  },
  {
    "path": "provider/provider/provider.go",
    "content": "/*\nCopyright © 2020 Christian Korneck <christian@korneck.de>\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n*/\n\npackage provider\n\n//Provider interface\ntype Provider interface {\n\t//GetAuthident - returns the key name under which the provider credentials are stored in Docker's credentials store. Special values: __SERVERNAME__ = use servername, __NONE__ = retrieving credentials will be handled by the provider\n\tGetAuthident() (authident string)\n\t//Pushrm function - main provider function, performs the api  call to update the repo description\n\tPushrm(servername string, namespacename string, reponame string, tagname string, dockerUser string, dockerPasswd string, readme string, shortdesc string) error\n}\n"
  },
  {
    "path": "provider/quay/quay.go",
    "content": "/*\nCopyright © 2020 Christian Korneck <christian@korneck.de>\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n*/\n\npackage quay\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"io/ioutil\"\n\t\"net/http\"\n\t\"strings\"\n\n\t\"github.com/christian-korneck/docker-pushrm/util\"\n\tlog \"github.com/sirupsen/logrus\"\n)\n\n//Quay struct\ntype Quay struct {\n}\n\n//Pushrm is the main provider function\nfunc (f Quay) Pushrm(servername string, namespacename string, reponame string, tagname string, dockerUser string, dockerPasswd string, readme string, shortdesc string) error {\n\n\tif shortdesc != \"\" {\n\t\tlog.Warn(\"Short description not supported for provider \\\"quay\\\". Ignoring.\")\n\t}\n\n\tlog.Debug(\"Quay.Pushrm called\")\n\n\tapikey, err := util.GetApikey(servername)\n\tif err != nil {\n\t\treturn fmt.Errorf(err.Error())\n\t}\n\t//log.Debug(\"apikey: \" + apikey)\n\tlog.Debug(\"apikey: \" + \"********\")\n\n\terr = PatchDescription(apikey, readme, servername, namespacename, reponame)\n\tif err != nil {\n\t\tlog.Debug(err)\n\t\treturn fmt.Errorf(\"error pushing readme to repo server. See error message below. Run with \\\"--debug\\\" for more details. \\n\\n\" + err.Error())\n\t}\n\n\treturn nil\n}\n\n//GetAuthident returns authident for local Docker credentials store\nfunc (f Quay) GetAuthident() (authident string) {\n\tlog.Debug(\"Quay.GetAuthident called\")\n\tauthident = \"__NONE__\"\n\treturn\n}\n\n//PatchDescription - api call to update the repo description\nfunc PatchDescription(quaytoken string, readme string, servername string, namespacename string, reponame string) (error error) {\n\n\tapiurl := \"https://\" + servername + \"/api/v1/repository/\" + namespacename + \"/\" + reponame\n\tmethod := \"PUT\"\n\n\tjsonbody, _ := json.Marshal(map[string]string{\"description\": readme})\n\tpayload := strings.NewReader(string(jsonbody))\n\n\tclient := &http.Client{}\n\treq, err := http.NewRequest(method, apiurl, payload)\n\tif err != nil {\n\t\tlog.Debug(err)\n\t\treturn fmt.Errorf(\"error pushing README, error creating http request\")\n\t}\n\n\treq.Header.Add(\"Authorization\", \"Bearer \"+quaytoken)\n\treq.Header.Add(\"Content-Type\", \"application/json\")\n\n\tres, err := client.Do(req)\n\tif err != nil {\n\t\tlog.Debug(err)\n\t\treturn fmt.Errorf(\"error pushing README, error creating http request\")\n\t}\n\n\tdefer res.Body.Close()\n\tbody, err := ioutil.ReadAll(res.Body)\n\tif err != nil {\n\t\tlog.Debug(err)\n\t\treturn fmt.Errorf(\"error pushing README, error reading response body\")\n\t}\n\n\tlog.Debug(\"push readme, response body: \" + string(body))\n\n\tvar dat map[string]interface{}\n\t// we need the json response only in case of failure to get the error message\n\tif res.StatusCode != 200 {\n\t\tif err := json.Unmarshal(body, &dat); err != nil {\n\t\t\tlog.Debug(err)\n\t\t}\n\t}\n\n\tlog.Debug(\"push README, status code: \", res.StatusCode)\n\n\tif res.StatusCode != 200 {\n\t\tmsg := \"error pushing README, bad status code for response: \" + res.Status\n\t\tif dat[\"error_message\"] != nil {\n\n\t\t\tmsg = msg + \". Server responded: \\\"\" + dat[\"error_message\"].(string) + \"\\\"\"\n\t\t}\n\t\tif res.StatusCode == 403 {\n\t\t\tmsg = msg + \". Try \\\"docker logout\\\" and \\\"docker login\\\"\"\n\n\t\t}\n\t\treturn fmt.Errorf(msg)\n\n\t} else {\n\t\tlog.Debug(\"status code OK, readme successfully pushed to repo server\")\n\t\treturn nil\n\t}\n\n}\n"
  },
  {
    "path": "util/util.go",
    "content": "/*\nCopyright © 2020 Christian Korneck <christian@korneck.de>\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n*/\n\npackage util\n\nimport (\n\t\"encoding/base64\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"io\"\n\t\"io/ioutil\"\n\t\"os\"\n\t\"os/exec\"\n\t\"path/filepath\"\n\t\"strings\"\n\n\tlog \"github.com/sirupsen/logrus\"\n\n\t\"github.com/spf13/viper\"\n)\n\n// BytesToString converts\nfunc BytesToString(b []byte) string {\n\treturn string(b[:])\n}\n\n// StringInSlice checks if a string exists in a slice\nfunc StringInSlice(checkval string, list []string) bool {\n\tfor _, b := range list {\n\t\tif b == checkval {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\n// ReadFile reads a file\nfunc ReadFile(path string) (filecontent string, error error) {\n\tcontent, err := ioutil.ReadFile(path)\n\tif err != nil {\n\t\tlog.Debug(err)\n\t\treturn \"\", fmt.Errorf(\"could not read README file: \" + path)\n\t}\n\ttext := string(content)\n\treturn text, nil\n}\n\n//GetApikey retrieves an API key from env var or the local Docker config file\nfunc GetApikey(servername string) (apikey string, error error) {\n\tlog.Debug(\"util.GetApikey called\")\n\n\tgenericEnvval := os.Getenv(\"DOCKER_APIKEY\")\n\tif genericEnvval != \"\" {\n\t\treturn genericEnvval, nil\n\t}\n\n\tenvkey := \"APIKEY__\" + strings.ToUpper(strings.Replace(servername, \".\", \"_\", -1))\n\tquerykey := \"plugins.docker-pushrm.apikey_\" + servername\n\n\tenvval := os.Getenv(envkey)\n\n\tif envval != \"\" {\n\t\tapikey = envval\n\t\treturn apikey, nil\n\t} else {\n\t\tcfgval := viper.GetString(querykey)\n\t\tif cfgval != \"\" {\n\t\t\tapikey = cfgval\n\t\t\treturn apikey, nil\n\t\t} else {\n\t\t\treturn \"\", fmt.Errorf(\"could not find api key for server \" + servername + \". Either specify env var DOCKER_APIKEY or env var \" + envkey + \" or \" + querykey + \" in the local Docker config file. \")\n\t\t}\n\n\t}\n\n}\n\n//GetDockerCreds retrieves credentials from the Docker creds store\nfunc GetDockerCreds(authident string, authidentIsFuzzy bool) (dockerUser string, dockerPasswd string, error error) {\n\n\tvar candidates []string\n\tif authidentIsFuzzy == true {\n\t\tcandidates = []string{authident, (\"https://\" + authident), (\"https://\" + authident + \"/\"), (\"http://\" + authident), (\"http://\" + authident + \"/\")}\n\t} else {\n\t\tcandidates = []string{authident}\n\t}\n\tfor _, candidate := range candidates {\n\t\tdockerUser, dockerPasswd = \"\", \"\"\n\t\tdockerUser, dockerPasswd, err := QueryDockerCreds(candidate)\n\t\tif err != nil {\n\t\t\tlog.Debug(\"tried candidate \" + candidate + \", got error: \" + err.Error())\n\t\t}\n\n\t\tif dockerUser == \"\" && dockerPasswd == \"\" {\n\t\t\tlog.Debug(\"tried candidate \" + candidate + \": could not find credentials\")\n\t\t} else {\n\t\t\tlog.Debug(\"tried candidate \" + candidate + \": found credentials for user \" + dockerUser)\n\t\t\treturn dockerUser, dockerPasswd, nil\n\t\t}\n\n\t}\n\n\treturn \"\", \"\", fmt.Errorf(\"no Docker credentials found for this server/provider. Run 'docker login' first. \")\n\n}\n\n//QueryDockerCreds fetches credentials for an authid\nfunc QueryDockerCreds(authident string) (dockerUser string, dockerPasswd string, error error) {\n\n\tlog.Debug(\"util.GetDockerCreds called\")\n\n\tif viper.GetString(\"auths.\"+authident+\".auth\") != \"\" {\n\n\t\tcredsb64 := viper.GetString(\"auths.\" + authident + \".auth\")\n\t\tcredsclearb, err := base64.StdEncoding.DecodeString(credsb64)\n\t\tif err != nil {\n\t\t\tlog.Debug(err)\n\t\t\treturn \"\", \"\", fmt.Errorf(\"Error parsing auth info from the Docker config file. Check your local Docker config. \")\n\t\t}\n\t\tcredsclear := string(credsclearb)\n\t\tcredssplit := strings.Split(credsclear, \":\")\n\t\tdockerUser = credssplit[0]\n\t\tdockerPasswd = credsclear[len(dockerUser)+1:]\n\n\t} else {\n\t\tif viper.GetString(\"credsStore\") != \"\" {\n\t\t\texecutable := \"docker-credential-\" + viper.GetString(\"credsStore\")\n\t\t\tif viper.GetString(\"credsStore\") == \"wincred\" {\n\t\t\t\texecutable = executable + \".exe\"\n\t\t\t}\n\t\t\tshx := exec.Command(executable, \"get\")\n\t\t\tstdin, err := shx.StdinPipe()\n\t\t\tif err != nil {\n\t\t\t\tlog.Debug(err)\n\t\t\t\treturn \"\", \"\", fmt.Errorf(\"Error executing the Docker credentials helper. Check your local Docker config and/or installation. \")\n\t\t\t}\n\n\t\t\tdone := make(chan bool)\n\n\t\t\tgo func() {\n\t\t\t\tdefer func() { done <- true }()\n\t\t\t\tdefer stdin.Close()\n\t\t\t\tio.WriteString(stdin, authident)\n\n\t\t\t}()\n\n\t\t\t<-done\n\n\t\t\tout, err := shx.CombinedOutput()\n\t\t\tif err != nil {\n\t\t\t\tlog.Debug(err)\n\t\t\t\treturn \"\", \"\", fmt.Errorf(\"no Docker credentials found for this server/provider. Run 'docker login' first. \")\n\t\t\t}\n\n\t\t\tvar dat map[string]interface{}\n\t\t\tif err := json.Unmarshal(out, &dat); err != nil {\n\t\t\t\tlog.Debug(err)\n\t\t\t\treturn \"\", \"\", fmt.Errorf(\"Error parsing credentials from Docker creds provider. Run 'docker login' first. \")\n\t\t\t}\n\t\t\tdockerUser = dat[\"Username\"].(string)\n\t\t\tdockerPasswd = dat[\"Secret\"].(string)\n\n\t\t} else {\n\t\t\treturn \"\", \"\", fmt.Errorf(\"no Docker credentials found for this server/provider. Run 'docker login' first. \")\n\t\t}\n\t}\n\n\treturn dockerUser, dockerPasswd, nil\n}\n\n//FindReadmeFile trys to find a readme file in the cwd\nfunc FindReadmeFile() (foundfile string, error error) {\n\tpreferedfilenames := []string{\"./README-containers.md\", \"./README.md\"} //prefer these filenames in this order\n\n\tfor _, preferedfilename := range preferedfilenames {\n\t\tmatches, err := filepath.Glob(preferedfilename)\n\t\tif err != nil {\n\t\t\tlog.Debug(err)\n\t\t\treturn \"\", fmt.Errorf(\"error while searching for default readme file\")\n\t\t}\n\t\tif len(matches) >= 1 {\n\t\t\tfoundfile = preferedfilename\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif foundfile == \"\" {\n\t\tmatches, err := filepath.Glob(\"./[R|r][E|e][A|a][D|d][M|m][E|e]*\")\n\t\tif err != nil {\n\t\t\tlog.Debug(err)\n\t\t\treturn \"\", fmt.Errorf(\"error while searching for alternate readme file\")\n\t\t}\n\t\tif len(matches) < 1 {\n\t\t\treturn \"\", fmt.Errorf(\"README file not found in the current working directory. Create a file \\\"README-containers.md\\\" or \\\"README.md\\\" or \\\"cd\\\" into a directory that contains a README file. \")\n\t\t} else {\n\t\t\tfoundfile = matches[0]\n\t\t}\n\t}\n\n\treturn foundfile, nil\n}\n"
  }
]