diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..ff1fe4e --- /dev/null +++ b/.gitattributes @@ -0,0 +1,15 @@ +# Auto detect text files and perform LF normalization +* text=auto + +# Collapse vendored and generated files on GitHub +vendor/* linguist-vendored +rules.mk linguist-vendored +*/vendor/* linguist-vendored +*.gen.* linguist-generated +*.pb.go linguist-generated +go.sum linguist-generated +go.mod linguist-generated +gen.sum linguist-generated + +# Reduce conflicts on markdown files +*.md merge=union diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 0000000..968eb12 --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1 @@ +* @unisack-org diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 1899438..606d6d1 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -1,24 +1,31 @@ --- name: Bug report -about: For reporting bugs in go-micro -title: "[BUG]" -labels: '' +about: Create a report to help us improve +title: "[BUG] " +labels: bug assignees: '' --- **Describe the bug** +A clear and concise description of what the bug is. -1. What are you trying to do? -2. What did you expect to happen? -3. What happens instead? +**To Reproduce** +Steps to reproduce the behavior: +1. Go to '...' +2. Type '....' +3. See error -**How to reproduce the bug:** +**Expected behavior** +A clear and concise description of what you expected to happen. -If possible, please include a minimal code snippet here. +**Screenshots / Logs** +If applicable, add screenshots or logs to help explain your problem. -**Environment:** -Go Version: please paste `go version` output here -``` -please paste `go env` output here -``` +**Versions (please complete the following information, if relevant):** +- Software version: [e.g. v1.2.3, latest, building from sources] +- OS: [e.g. Ubuntu, Mac, iOS, ...] +- Golang version [e.g. 1.13] + +**Additional context** +Add any other context about the problem here. diff --git a/.github/ISSUE_TEMPLATE/feature-request---enhancement.md b/.github/ISSUE_TEMPLATE/feature_request.md similarity index 61% rename from .github/ISSUE_TEMPLATE/feature-request---enhancement.md rename to .github/ISSUE_TEMPLATE/feature_request.md index 459817f..3f27c3f 100644 --- a/.github/ISSUE_TEMPLATE/feature-request---enhancement.md +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -1,8 +1,8 @@ --- -name: Feature request / Enhancement -about: If you have a need not served by go-micro -title: "[FEATURE]" -labels: '' +name: Feature request +about: Suggest an idea for this project +title: "[IDEA] " +labels: enhancement assignees: '' --- @@ -13,5 +13,8 @@ A clear and concise description of what the problem is. Ex. I'm always frustrate **Describe the solution you'd like** A clear and concise description of what you want to happen. +**Describe alternatives you've considered** +A clear and concise description of any alternative solutions or features you've considered. + **Additional context** Add any other context or screenshots about the feature request here. diff --git a/.github/ISSUE_TEMPLATE/question.md b/.github/ISSUE_TEMPLATE/question.md deleted file mode 100644 index 1daf48b..0000000 --- a/.github/ISSUE_TEMPLATE/question.md +++ /dev/null @@ -1,14 +0,0 @@ ---- -name: Question -about: Ask a question about go-micro -title: '' -labels: '' -assignees: '' - ---- - -Before asking, please check if your question has already been answered: - -1. Check the documentation - https://micro.mu/docs/ -2. Check the examples and plugins - https://github.com/micro/examples & https://github.com/micro/go-plugins -3. Search existing issues diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index cba3cbc..ebc63af 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,9 +1,9 @@ -## Pull Request template -Please, go through these steps before clicking submit on this PR. + diff --git a/.github/dependabot.yml b/.github/dependabot.yml deleted file mode 100644 index d5f7eae..0000000 --- a/.github/dependabot.yml +++ /dev/null @@ -1,19 +0,0 @@ -# To get started with Dependabot version updates, you'll need to specify which -# package ecosystems to update and where the package manifests are located. -# Please see the documentation for all configuration options: -# https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates - -version: 2 -updates: - - # Maintain dependencies for GitHub Actions - - package-ecosystem: "github-actions" - directory: "/" - schedule: - interval: "daily" - - # Maintain dependencies for Golang - - package-ecosystem: "gomod" - directory: "/" - schedule: - interval: "daily" diff --git a/.github/renovate.json b/.github/renovate.json new file mode 100644 index 0000000..52d2918 --- /dev/null +++ b/.github/renovate.json @@ -0,0 +1,19 @@ +{ + "extends": [ + "config:base" + ], + "packageRules": [ + { + "matchUpdateTypes": ["minor", "patch", "pin", "digest"], + "automerge": true + }, + { + "groupName": "all deps", + "separateMajorMinor": true, + "groupSlug": "all", + "packagePatterns": [ + "*" + ] + } + ] +} diff --git a/.github/workflows/autoapprove.yml b/.github/workflows/autoapprove.yml deleted file mode 100644 index 5bf5d9f..0000000 --- a/.github/workflows/autoapprove.yml +++ /dev/null @@ -1,20 +0,0 @@ -name: "autoapprove" - -on: - pull_request_target: - types: [assigned, opened, synchronize, reopened] - -permissions: - pull-requests: write - contents: write - -jobs: - autoapprove: - runs-on: ubuntu-latest - steps: - - name: approve - uses: hmarr/auto-approve-action@v3 - if: github.actor == 'vtolstov' || github.actor == 'dependabot[bot]' - id: approve - with: - github-token: ${{ secrets.GITHUB_TOKEN }} \ No newline at end of file diff --git a/.github/workflows/automerge.yml b/.github/workflows/automerge.yml deleted file mode 100644 index 5ff3f69..0000000 --- a/.github/workflows/automerge.yml +++ /dev/null @@ -1,21 +0,0 @@ -name: "automerge" - -on: - pull_request_target: - types: [assigned, opened, synchronize, reopened] - -permissions: - pull-requests: write - contents: write - -jobs: - automerge: - runs-on: ubuntu-latest - if: github.actor == 'vtolstov' - steps: - - name: merge - id: merge - run: gh pr merge --auto --merge "$PR_URL" - env: - PR_URL: ${{github.event.pull_request.html_url}} - GITHUB_TOKEN: ${{secrets.TOKEN}} diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml deleted file mode 100644 index 9603352..0000000 --- a/.github/workflows/build.yml +++ /dev/null @@ -1,47 +0,0 @@ -name: build -on: - push: - branches: - - master - - v3 -jobs: - test: - name: test - runs-on: ubuntu-latest - steps: - - name: setup - uses: actions/setup-go@v3 - with: - go-version: 1.17 - - name: checkout - uses: actions/checkout@v3 - - name: cache - uses: actions/cache@v3 - with: - path: ~/go/pkg/mod - key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} - restore-keys: ${{ runner.os }}-go- - - name: deps - run: go get -v -t -d ./... - - name: test - env: - INTEGRATION_TESTS: yes - run: go test -mod readonly -v ./... - lint: - name: lint - runs-on: ubuntu-latest - steps: - - name: checkout - uses: actions/checkout@v3 - - name: lint - uses: golangci/golangci-lint-action@v3.4.0 - continue-on-error: true - with: - # Required: the version of golangci-lint is required and must be specified without patch version: we always use the latest patch version. - version: v1.30 - # Optional: working directory, useful for monorepos - # working-directory: somedir - # Optional: golangci-lint command line arguments. - # args: --issues-exit-code=0 - # Optional: show only new issues if it's a pull request. The default value is `false`. - # only-new-issues: true diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml deleted file mode 100644 index 2f6c6de..0000000 --- a/.github/workflows/codeql-analysis.yml +++ /dev/null @@ -1,78 +0,0 @@ -# For most projects, this workflow file will not need changing; you simply need -# to commit it to your repository. -# -# You may wish to alter this file to override the set of languages analyzed, -# or to provide custom queries or build logic. -# -# ******** NOTE ******** -# We have attempted to detect the languages in your repository. Please check -# the `language` matrix defined below to confirm you have the correct set of -# supported CodeQL languages. -# -name: "codeql" - -on: - workflow_run: - workflows: ["prbuild"] - types: - - completed - push: - branches: [ master, v3 ] - pull_request: - # The branches below must be a subset of the branches above - branches: [ master, v3 ] - schedule: - - cron: '34 1 * * 0' - -jobs: - analyze: - name: analyze - runs-on: ubuntu-latest - permissions: - actions: read - contents: read - security-events: write - - strategy: - fail-fast: false - matrix: - language: [ 'go' ] - # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ] - # Learn more: - # https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed - - steps: - - name: checkout - uses: actions/checkout@v3 - - name: setup - uses: actions/setup-go@v3 - with: - go-version: 1.17 - # Initializes the CodeQL tools for scanning. - - name: init - uses: github/codeql-action/init@v2 - with: - languages: ${{ matrix.language }} - # If you wish to specify custom queries, you can do so here or in a config file. - # By default, queries listed here will override any specified in a config file. - # Prefix the list here with "+" to use these queries and those in the config file. - # queries: ./path/to/local/query, your-org/your-repo/queries@main - - # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). - # If this step fails, then you should remove it and run the build manually (see below) - - name: autobuild - uses: github/codeql-action/autobuild@v2 - - # ℹ️ Command-line programs to run using the OS shell. - # 📚 https://git.io/JvXDl - - # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines - # and modify them (or add more) to build your code if your project - # uses a compiled language - - #- run: | - # make bootstrap - # make release - - - name: analyze - uses: github/codeql-action/analyze@v2 diff --git a/.github/workflows/dependabot-automerge.yml b/.github/workflows/dependabot-automerge.yml deleted file mode 100644 index f41c1c0..0000000 --- a/.github/workflows/dependabot-automerge.yml +++ /dev/null @@ -1,27 +0,0 @@ -name: "dependabot-automerge" - -on: - pull_request_target: - types: [assigned, opened, synchronize, reopened] - -permissions: - pull-requests: write - contents: write - -jobs: - automerge: - runs-on: ubuntu-latest - if: github.actor == 'dependabot[bot]' - steps: - - name: metadata - id: metadata - uses: dependabot/fetch-metadata@v1.3.6 - with: - github-token: "${{ secrets.TOKEN }}" - - name: merge - id: merge - if: ${{contains(steps.metadata.outputs.dependency-names, 'go.unistack.org')}} - run: gh pr merge --auto --merge "$PR_URL" - env: - PR_URL: ${{github.event.pull_request.html_url}} - GITHUB_TOKEN: ${{secrets.TOKEN}} diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml deleted file mode 100644 index f313ebe..0000000 --- a/.github/workflows/pr.yml +++ /dev/null @@ -1,47 +0,0 @@ -name: prbuild -on: - pull_request: - branches: - - master - - v3 -jobs: - test: - name: test - runs-on: ubuntu-latest - steps: - - name: setup - uses: actions/setup-go@v3 - with: - go-version: 1.17 - - name: checkout - uses: actions/checkout@v3 - - name: cache - uses: actions/cache@v3 - with: - path: ~/go/pkg/mod - key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} - restore-keys: ${{ runner.os }}-go- - - name: deps - run: go get -v -t -d ./... - - name: test - env: - INTEGRATION_TESTS: yes - run: go test -mod readonly -v ./... - lint: - name: lint - runs-on: ubuntu-latest - steps: - - name: checkout - uses: actions/checkout@v3 - - name: lint - uses: golangci/golangci-lint-action@v3.4.0 - continue-on-error: true - with: - # Required: the version of golangci-lint is required and must be specified without patch version: we always use the latest patch version. - version: v1.30 - # Optional: working directory, useful for monorepos - # working-directory: somedir - # Optional: golangci-lint command line arguments. - # args: --issues-exit-code=0 - # Optional: show only new issues if it's a pull request. The default value is `false`. - # only-new-issues: true diff --git a/.gitignore b/.gitignore index 0ee6fc0..772d6c2 100644 --- a/.gitignore +++ b/.gitignore @@ -1,38 +1,27 @@ -# Develop tools -/.vscode/ -/.idea/ +# Temporary files +*~ +*# +.#* +coverage.txt + +# Vendors +package-lock.json +node_modules/ +vendor/ # Binaries for programs and plugins +dist/ +gin-bin *.exe *.exe~ *.dll *.so *.dylib -# Folders -_obj -_test -_build - -# Architecture specific extensions/prefixes -*.[568vq] -[568vq].out - -*.cgo1.go -*.cgo2.c -_cgo_defun.c -_cgo_gotypes.go -_cgo_export.* - # Test binary, build with `go test -c` *.test # Output of the go coverage tool, specifically when used with LiteIDE *.out - -# vim temp files -*~ -*.swp -*.swo -/protoc-gen-go-micro +/protoc-gen-micro diff --git a/.golangci.yml b/.golangci.yml new file mode 100644 index 0000000..cf01fa4 --- /dev/null +++ b/.golangci.yml @@ -0,0 +1,34 @@ +run: + deadline: 1m + tests: false + #skip-files: + # - ".*\\.gen\\.go" + +linters-settings: + golint: + min-confidence: 0 + maligned: + suggest-new: true + goconst: + min-len: 5 + min-occurrences: 4 + misspell: + locale: US + +linters: + disable-all: true + enable: + - goconst + - misspell + - deadcode + - misspell + - structcheck + - errcheck + - unused + - varcheck + - staticcheck + - unconvert + - gofmt + - goimports + - golint + - ineffassign diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 0000000..830544e --- /dev/null +++ b/AUTHORS @@ -0,0 +1,28 @@ +# This file lists all individuals having contributed content to the repository. + +Alexandre Beslic +Anastasia DERUELLE +Gero +gfanton +Guilhem Fanton +Jan Weitz +jhayotte +Julien Hayotte +Manfred Touron +Mathieu Acthernoene +Mike Lee +moul-bot <41326314+moul-bot@users.noreply.github.com> +Pat Moroney +Pat Moroney +Peter Monko +Pierre Roullon +Quentin Perez +Renovate Bot +Sacha Froment +Shogo Iwano +Thomas KERAMBLOCH +Tommy PAGEARD +Valerio Gheri +Victor Login +webii +Vasiliy Tolstov diff --git a/LICENSE b/LICENSE index 9dbed63..59b4d49 100644 --- a/LICENSE +++ b/LICENSE @@ -1,191 +1,23 @@ +MIT License - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ +Copyright (c) 2016-2021 Manfred Touron +Copyright (c) 2021 Unistack LLC - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - 1. Definitions. +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - Copyright 2021 Unistack LLC. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md index ec9b91d..faca57d 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ -# `protoc-gen-go-micro` -protobuf plugin to generate helper code for micro framework +# `protoc-gen-micro` +:open_file_folder: protocol generator + golang text/template (protobuf) A generic **code**/script/data generator based on [Protobuf](https://developers.google.com/protocol-buffers/). @@ -7,20 +7,129 @@ A generic **code**/script/data generator based on [Protobuf](https://developers. This project is a generator plugin for the Google Protocol Buffers compiler (`protoc`). +The plugin parses **protobuf** files, generates an **ast**, and walks a local **templates directory** to generate files using the [Golang's `text/template` engine](https://golang.org/pkg/text/template/). + +## Philosophy + +* protobuf-first +* no built-in template, only user defined templates +* kiss, *keep it stupid simple* + +## Under the hood + +1. the *user* `protobuf` files are parsed by [`protoc`](https://github.com/google/protobuf/releases) +2. the `ast` is generated by [`protoc-gen-go` helpers](https://github.com/golang/protobuf/tree/master/protoc-gen-go) +3. the `ast` is given to [Golang's `text/template` engine](https://golang.org/pkg/text/template/) for each *user* template files +4. the *funcmap* enriching the template engine is based on [Masterminds/sprig](https://github.com/Masterminds/sprig), and contains type-manipulation, iteration and language-specific helpers + ## Usage +`protoc-gen-micro` requires a **template_dir** directory *(by default `./templates`)*. + +Every file ending with `.tmpl` will be processed and written to the destination folder, following the file hierarchy of the `template_dir`, and remove the `.tmpl` extension. + +--- + ```console -$> protoc --go_micro_out=debug=true,components="micro|http":. input.proto +$> ls -R +input.proto templates/doc.txt.tmpl templates/config.json.tmpl +$> protoc --micro_out=. input.proto +$> ls -R +input.proto templates/doc.txt.tmpl templates/config.json.tmpl +doc.txt config.json +``` + +### Options + +You can specify custom options, as follow: + +```console +$> protoc --micro_out=debug=true,template_dir=/path/to/template/directory:. input.proto ``` | Option | Default Value | Accepted Values | Description |-----------------------|---------------|---------------------------|----------------------- -| `tag_path` | `.` | `any local path` | path contains generated protobuf code that needs to be tagged +| `template_repo` | `` | url in form schema://domain | path to repo with optional branch or revision after @ sign +| `template_dir`       | `./template` | absolute or relative path | path to look for templates +| `destination_dir`     | `.`           | absolute or relative path | base path to write output +| `single-package-mode` | *false* | `true` or `false` | if *true*, `protoc` won't accept multiple packages to be compiled at once (*!= from `all`*), but will support `Message` lookup across the imported protobuf dependencies | `debug`               | *false*       | `true` or `false` | if *true*, `protoc` will generate a more verbose output -| `components` | `micro` | `micro rpc http chi gorilla client server` | some values can't coexists like gorilla/chi or rpc/http, values must be concatinated with pipe symbol +| `all`                 | *false*       | `true` or `false`         | if *true*, protobuf files without `Service` will also be parsed +| `components` | `micro` | `micro|grpc|http|chi|gorilla` | some values cant coexists like gorilla/chi or grpc/http + +##### Hints + +Shipping the templates with your project is very smart and useful when contributing on git-based projects. + +Another workflow consists in having a dedicated repository for generic templates which is then versioned and vendored with multiple projects (npm package, golang vendor package, ...) + +## Funcmap + +This project uses [Masterminds/sprig](https://github.com/Masterminds/sprig) library and additional functions to extend the builtin [text/template](https://golang.org/pkg/text/template) helpers. + +Non-exhaustive list of new helpers: + +* **all the functions from [sprig](https://github.com/Masterminds/sprig)** +* `add` +* `boolFieldExtension` +* `camelCase` +* `contains` +* `divide` +* `fieldMapKeyType` +* `fieldMapValueType` +* `first` +* `getEnumValue` +* `getMessageType` +* `getProtoFile` +* `goNormalize` +* `goTypeWithPackage` +* `goType` +* `goZeroValue` +* `haskellType` +* `httpBody` +* `httpPath` +* `httpPathsAdditionalBindings` +* `httpVerb` +* `index` +* `int64FieldExtension` +* `isFieldMap` +* `isFieldMessageTimeStamp` +* `isFieldMessage` +* `isFieldRepeated` +* `jsSuffixReserved` +* `jsType` +* `json` +* `kebabCase` +* `last` +* `leadingComment` +* `leadingDetachedComments` +* `lowerCamelCase` +* `lowerFirst` +* `lowerGoNormalize` +* `multiply` +* `namespacedFlowType` +* `prettyjson` +* `replaceDict` +* `shortType` +* `snakeCase` +* `splitArray` +* `stringFieldExtension` +* `stringMethodOptionsExtension` +* `string` +* `subtract` +* `trailingComment` +* `trimstr` +* `upperFirst` +* `urlHasVarsFromMessage` + +See the project helpers for the complete list. ## Install -* Install the **go** compiler and tools from https://golang.org/doc/install -* Install **protoc-gen-go**: `go install google.golang.org/protobuf/cmd/protoc-gen-go` -* Install **protoc-gen-go-micro**: `go install go.unistack.org/protoc-gen-go-micro/v4` +* Install the **Go** compiler and tools from https://golang.org/doc/install +* Install **protobuf**: `go get -u github.com/golang/protobuf/{proto,protoc-gen-go}` +* Install **protoc-gen-micro**: `go get -u github.com/unistack-org/protoc-gen-micro` + +## License + +MIT diff --git a/assets.go b/assets.go new file mode 100644 index 0000000..8554773 --- /dev/null +++ b/assets.go @@ -0,0 +1,22 @@ +// +build dev + +package main + +import ( + "log" + + "github.com/shurcooL/vfsgen" + "github.com/unistack-org/protoc-gen-micro/v3/assets" +) + +func main() { + err := vfsgen.Generate(assets.Assets, vfsgen.Options{ + PackageName: "assets", + BuildTags: "!dev", + VariableName: "Assets", + Filename: "assets/vfsdata.go", + }) + if err != nil { + log.Fatal(err) + } +} diff --git a/assets/assets.go b/assets/assets.go new file mode 100644 index 0000000..0312b5f --- /dev/null +++ b/assets/assets.go @@ -0,0 +1,20 @@ +// +build dev + +package assets + +import ( + "go/build" + "log" + "net/http" +) + +func importPathToDir(importPath string) string { + p, err := build.Import(importPath, "", build.FindOnly) + if err != nil { + log.Fatal(err) + } + return p.Dir +} + +// Assets contains the project's assets. +var Assets http.FileSystem = http.Dir("./templates") diff --git a/assets/stub.go b/assets/stub.go new file mode 100644 index 0000000..b1b684d --- /dev/null +++ b/assets/stub.go @@ -0,0 +1 @@ +package assets diff --git a/assets/vfsdata.go b/assets/vfsdata.go new file mode 100644 index 0000000..6a0d79d --- /dev/null +++ b/assets/vfsdata.go @@ -0,0 +1,218 @@ +// Code generated by vfsgen; DO NOT EDIT. + +// +build !dev + +package assets + +import ( + "bytes" + "compress/gzip" + "fmt" + "io" + "io/ioutil" + "net/http" + "os" + pathpkg "path" + "time" +) + +// Assets statically implements the virtual filesystem provided to vfsgen. +var Assets = func() http.FileSystem { + fs := vfsgen۰FS{ + "/": &vfsgen۰DirInfo{ + name: "/", + modTime: time.Date(2021, 2, 2, 14, 12, 44, 397557820, time.UTC), + }, + "/e3suU2VydmljZS5OYW1lIHwgdHJpbVN1ZmZpeCAiU2VydmljZSIgfCBsb3dlcn19X21pY3JvX2NoaS5wYi5nby50bXBs": &vfsgen۰CompressedFileInfo{ + name: "e3suU2VydmljZS5OYW1lIHwgdHJpbVN1ZmZpeCAiU2VydmljZSIgfCBsb3dlcn19X21pY3JvX2NoaS5wYi5nby50bXBs", + modTime: time.Date(2021, 2, 2, 13, 20, 50, 293162978, time.UTC), + uncompressedSize: 1649, + + compressedContent: []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x02\xff\xa4\x54\x61\x6f\xdb\x36\x10\xfd\x6c\xfe\x8a\x1b\x87\x00\x52\xaa\x50\x2b\xb6\x4f\x5e\xfb\x61\x2b\x52\x20\xd8\xda\x15\xe9\xd0\x02\x0b\x82\x80\xa1\x4e\x12\x61\x89\xd4\xc8\x93\x27\x43\xd6\x7f\x1f\x28\xd1\x71\x5a\xb7\xc1\xb0\x1a\x30\x24\x92\xef\xdd\xdd\xbb\x7b\x62\x9e\xc3\x2b\x5b\x20\x54\x68\xd0\x49\xc2\x02\xee\x77\xd0\x39\x4b\x56\x5d\x54\x68\x2e\x5a\xad\x9c\x65\x79\x0e\xde\xf6\x4e\xe1\x1a\xc6\x51\xbc\xd6\x0d\x8a\xb7\xb2\xc5\x69\x62\x9d\x54\x1b\x59\x21\x8c\x63\x65\xdf\x6d\xaa\xdf\xa5\xa7\xcb\x06\x5b\x34\x04\x33\x0e\xf6\xe0\xbb\x46\xd3\x2f\xce\xc9\x1d\xf0\x9f\x39\xec\xa1\x91\x9e\x60\x0f\x0e\xbb\x46\x2a\x04\x2e\x38\xf0\x3b\x3e\x4d\x8c\xe9\xb6\xb3\x8e\x20\x61\x00\x5c\x59\x43\x38\x10\x0f\xef\x65\xbb\x3c\x0d\x52\x5e\x13\x75\xf3\xc2\x61\xd9\xa0\x5a\x0e\x3c\x39\x6d\x2a\xcf\x19\x5b\xf1\x4a\x53\xdd\xdf\x0b\x65\xdb\xbc\xb2\x17\xaa\xd6\x79\xf8\x6f\x7f\xe2\x6c\xd5\xea\xa2\x68\xf0\x1f\xe9\x10\xbe\x0a\xcb\x8f\xa0\x99\xa1\x9c\xbd\x93\x9d\xfe\x84\xd0\x1b\xed\x49\xaa\xcd\x85\x75\x55\x3e\x43\xf2\xed\x8f\xb9\xec\x34\x67\x29\x63\xb4\xeb\x10\x9c\xed\x09\x7f\xc3\x1d\x78\x72\xbd\xa2\x71\x62\xac\xec\x8d\x82\xeb\xb0\x1f\x9a\x97\x28\x1a\x20\x8a\x14\xaf\x96\x67\x0a\xc9\xa2\x24\x83\x7b\x6b\x9b\x14\x46\x06\xf1\xb7\x95\x4d\x8f\x19\xd8\x0d\xac\x5f\x82\xa2\x41\x7c\x08\x1b\xc9\x21\xcd\x38\xa5\x22\x72\xd3\x07\x8e\x43\xea\x9d\x39\x52\xd9\xa1\x88\x71\x14\xef\xd1\x6d\xb5\x5a\xe6\x08\x7b\x20\xa7\xdb\xf7\x7d\x59\xea\x01\x78\x3c\xe2\xd3\x14\xdf\xae\xb1\xd2\x9e\xd0\x25\x0e\xce\x55\xad\xc5\x9b\x7e\xc8\xa0\x06\x6d\x08\x5d\x29\x15\x8e\x53\x06\xd8\x79\xb8\xb9\x3d\x7f\xe8\x97\xb8\x34\x45\x67\xb5\xa1\x14\xd0\x39\xeb\x1e\x4b\x09\x12\xe2\xf4\x16\x19\x7f\x94\x49\x9d\xb2\x07\x80\x2e\x61\x2b\xde\xf6\xed\x1b\xa4\xda\x16\x49\x0a\x2f\xe0\xf9\x23\xfe\x67\xf2\xca\x96\xc4\x65\x48\x51\x26\xbc\x96\xa6\x68\xd0\x41\x2d\x3d\x18\x0b\xed\x1c\xc0\xaf\xe1\xec\x4f\x9e\x41\x7d\xec\xcc\x74\x4c\x56\x5a\x07\x77\xa1\xfe\xb9\x2a\x69\x2a\x9c\xb5\x9c\xa6\xd3\xc5\x10\x20\xd1\x6a\xe2\xca\x14\x38\x24\xd8\xcd\x1d\xcc\x82\x8b\xd3\x53\x4a\x39\xb3\x42\xf9\xfb\x3d\x34\x68\x0e\xf8\x14\x5e\xbc\x9c\x8f\x4e\xd3\x3c\xa1\x4e\x9b\xad\x6c\x74\x01\x8f\xdb\x0b\x46\xb6\xb8\x86\x33\xcf\x83\x86\x25\xf8\x49\xcc\xe9\x64\x27\xb0\x82\x9a\x48\xb9\xd1\xc5\xf0\xec\xf9\xfa\xf6\x04\xd7\x06\xd0\x56\x2c\x93\xf8\x75\x37\x1b\xd7\x7c\x31\x87\x2e\xe1\xbb\x56\x5c\xf9\x0f\xa1\xc4\x24\x0d\x82\xc3\xf2\x2f\x74\x36\x49\xff\x9f\xce\x38\xcd\x2c\xce\x11\xce\xc2\x50\x09\x4a\xdb\x9b\x82\x67\x60\xbe\xa2\xf5\xd4\x28\xf5\xe1\xc3\x69\xc5\xd5\xc1\xb4\x49\x2a\x92\xf0\x31\x24\xe1\x42\x11\xd7\xe8\x3b\x6b\x3c\x7e\x74\x9a\x42\xc6\xf3\xb8\xfb\x77\x8f\x9e\xd2\x2f\xab\xb5\x9b\x6f\x92\xb5\x86\xb3\xef\x9f\x6d\x79\xf6\x69\x51\xff\x65\x78\xd1\xb2\xb1\x2b\x8f\x6c\x1b\xe7\xf4\x54\x59\xe2\xa3\xa6\x3a\x39\xde\x71\xf3\xfa\xf3\xbb\xe4\x68\xa5\x34\x86\x7c\x1d\x3a\xb5\x24\x9c\x0f\xdf\x49\xaa\x6f\x7e\xb8\xcd\xc0\xd5\x4f\x55\x3c\xb1\xd5\x6a\x15\x5b\x61\x74\xc3\x26\xf6\x6f\x00\x00\x00\xff\xff\x49\x95\x41\x5f\x71\x06\x00\x00"), + }, + "/e3suU2VydmljZS5OYW1lIHwgdHJpbVN1ZmZpeCAiU2VydmljZSIgfCBsb3dlcn19X21pY3JvX2dvcmlsbGEucGIuZ28udG1wbA==": &vfsgen۰CompressedFileInfo{ + name: "e3suU2VydmljZS5OYW1lIHwgdHJpbVN1ZmZpeCAiU2VydmljZSIgfCBsb3dlcn19X21pY3JvX2dvcmlsbGEucGIuZ28udG1wbA==", + modTime: time.Date(2021, 2, 2, 13, 20, 17, 930071238, time.UTC), + uncompressedSize: 1334, + + compressedContent: []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x02\xff\xa4\x53\xd1\x4e\xdc\x3a\x10\x7d\x5e\x7f\xc5\x5c\x5f\xad\x94\x40\x70\x2e\xba\x6f\x5b\x78\x68\x2b\x50\x91\x5a\x8a\xa0\xa2\x52\x11\x42\x26\x19\x27\xd6\xc6\x76\x3a\x76\x56\x8b\x76\xf3\xef\x95\xb3\x81\x52\x85\x56\x55\x9b\x97\xd8\x9e\x33\x33\xe7\xf8\x8c\xf3\x1c\xde\xba\x12\xa1\x42\x8b\x24\x03\x96\x70\xff\x00\x2d\xb9\xe0\x8a\x83\x0a\xed\x81\xd1\x05\x39\x96\xe7\xe0\x5d\x47\x05\x2e\x60\xb3\x11\xa7\xba\x41\x71\x2e\x0d\xf6\x3d\x6b\x65\xb1\x94\x15\xc2\x66\x53\xb9\x8b\x65\xf5\x5e\xfa\x70\xd2\xa0\x41\x1b\x60\xc0\xc1\x16\x7c\xdb\xe8\xf0\x9a\x48\x3e\x00\x7f\xc5\x61\x0b\x8d\xf4\x01\xb6\x40\xd8\x36\xb2\x40\xe0\x82\x03\xbf\xe3\x7d\xcf\x98\x36\xad\xa3\x00\x09\x03\xe0\xca\x04\x1e\xff\x16\x43\x5e\x87\xd0\x0e\x1b\x42\xd5\x60\xb1\x0b\xf8\x40\xda\x56\x9e\x33\x36\xe3\x95\x0e\x75\x77\x2f\x0a\x67\xf2\xca\x91\x6e\x1a\x99\x9b\x6e\xcd\xd9\x6c\xe0\x7f\x27\x5b\x0d\xcf\x31\x9d\xd5\x3e\xc8\x62\x79\xe0\xa8\xca\x07\x48\xbe\xfa\x3f\x97\xad\xe6\x2c\x65\x4c\x75\xb6\x88\x3a\xaf\x90\x56\xba\xd8\x49\x85\x2d\x04\xd2\xe6\xaa\x53\x4a\xaf\x81\x8f\x21\xde\xf7\xe3\xea\x12\x2b\xed\x03\x52\x42\xb0\x67\xba\xb5\xb8\x74\x5d\x40\xca\xa0\x06\x6d\x03\x92\x92\x05\x6e\xfa\x0c\xb0\xf5\x70\x73\xbb\xf7\xc4\x4a\x9c\xd8\xb2\x75\xda\x86\x14\x90\xc8\x11\x6c\x18\x8c\xdf\x0a\x16\xc7\x30\xea\x15\xd7\xb2\xe9\xf0\xa3\x4a\xea\x94\x3d\x01\xb4\x82\x95\x38\xef\xcc\x07\x0c\xb5\x2b\x93\x14\x8e\xe0\xf0\x59\xfe\xe3\x47\x18\x3a\xb2\xa0\x4c\x10\x27\xb1\x85\x4a\x78\x2d\x6d\xd9\x20\x41\x2d\x3d\x58\x07\x66\x28\xe0\x17\x30\xff\xc4\x33\xa8\xd3\xa7\x12\xfd\xf7\x66\xca\x11\xdc\x45\xfe\x03\x2b\x69\x2b\x1c\xb4\x4c\xdb\xe9\x72\x1d\x21\xa3\x39\xe2\xcc\x96\xb8\x4e\xb0\x1d\x2e\x31\x8b\x5e\xa7\xd3\x14\x35\x64\x45\xfa\xdb\x2d\x34\x68\x1f\xf1\x29\x1c\x1d\x0f\xa1\x69\x9b\x5f\xa8\xd3\x76\x25\x1b\x5d\xc2\xf3\xeb\x05\x2b\x0d\x2e\x60\xee\x79\xd4\xb0\x2b\x3e\xa9\xd9\x4f\x4e\x62\x56\x54\x33\xa6\xdc\xe8\x72\xbd\x7f\xb8\xb8\x9d\xe0\x4c\x04\xad\xc4\xce\x89\x37\x0f\x11\x9b\xd8\x17\x7b\x68\x05\xff\x18\x71\xe6\xaf\x23\xc5\x24\x8d\x82\xe3\xf6\x0b\x92\x4b\xd2\x3f\xd3\x39\xba\x99\x8d\x3e\xc2\x3c\x9a\x1a\x40\xb9\xce\x96\x3c\x03\xfb\x13\xad\xd3\x41\xa9\x33\x70\xcb\xa8\xc4\x88\xb3\xc7\xa1\x4d\x52\x91\xc4\xf7\x90\xc4\x27\x28\x2e\xd1\xb7\xce\x7a\xfc\x4c\x7a\x98\xee\xbd\xf1\xf4\x6b\x87\x3e\xa4\x2f\xab\x75\xcb\xbf\x92\xb5\x80\xf9\xbf\xfb\x2b\x9e\xfd\x48\xea\x77\xcc\x23\xf1\x6e\x28\x71\x1a\xe9\x63\x2b\x2e\x64\xa8\x6f\xfe\xbb\xcd\x80\xea\x74\xb4\xca\xc7\xf3\xdd\x52\x08\x91\x0e\x26\x27\x93\xf9\xe8\xd9\x6c\x36\x1b\x99\x5a\xdd\xb0\x9e\x7d\x0b\x00\x00\xff\xff\x57\xf7\xa9\x27\x36\x05\x00\x00"), + }, + "/e3t0cmltU3VmZml4ICIucHJvdG8iIC5GaWxlLk5hbWV9fV9taWNyb19ncnBjLnBiLmdvLnRtcGw=": &vfsgen۰CompressedFileInfo{ + name: "e3t0cmltU3VmZml4ICIucHJvdG8iIC5GaWxlLk5hbWV9fV9taWNyb19ncnBjLnBiLmdvLnRtcGw=", + modTime: time.Date(2021, 2, 19, 13, 56, 2, 718469715, time.UTC), + uncompressedSize: 8947, + + compressedContent: []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x02\xff\xe4\x5a\x5b\x6f\xdb\x36\x14\x7e\x16\x7f\xc5\xa9\x30\x14\xd2\xa0\xc8\x0f\x7b\x4b\x91\x87\x22\x68\xb1\x01\x6b\x3a\x34\x03\xf6\x18\xa8\xf2\xb1\x4d\x54\xa2\x14\x92\x4e\x52\x28\xfc\xef\x03\x2f\xba\x5a\x96\xed\xd8\x6e\x8a\x2d\x0f\x35\x2c\xf2\xf0\x7c\xe7\xfe\x89\xee\x6c\x06\xd7\xc5\x1c\x61\x89\x0c\x79\x22\x71\x0e\x5f\xbf\x43\xc9\x0b\x59\xa4\x17\x4b\x64\x17\x39\x4d\x79\x41\x66\x33\x10\xc5\x9a\xa7\x78\x09\x55\x15\x7f\xa4\x19\xc6\x37\x49\x8e\x4a\x91\x32\x49\xbf\x25\x4b\x84\xaa\x5a\x16\x7f\x7d\x5b\xfe\x99\x08\xf9\x21\xc3\x1c\x99\x04\xb3\x0f\x9e\x41\x94\x19\x95\xef\x39\x4f\xbe\x83\xff\xce\x87\x67\xc8\x12\x21\xe1\x19\x38\x96\x59\x92\x22\xf8\xb1\x0f\xfe\x9d\xaf\x14\x21\x34\x2f\x0b\x2e\x21\x20\x9e\x9f\x16\x4c\xe2\x93\xf4\x09\x01\x30\x20\xee\x92\x92\x82\xbf\xa4\x72\xb5\xfe\x1a\xa7\x45\x3e\x5b\x33\x2a\x64\x92\x7e\xbb\x28\xf8\x72\x66\xb6\xcc\x1e\x7e\x9b\x25\x25\xf5\x89\x67\x25\xd2\x8c\x6a\x20\xbb\x85\xec\x46\x1f\x6a\x41\x81\xfc\x01\xf9\x1e\x82\x76\xa3\x4f\x42\x42\x1e\x12\x0e\x01\x01\x00\xb8\x83\xee\x29\xf1\xe7\x52\xd2\x82\xf5\x56\xac\xbe\x7a\x25\x24\xa4\xaa\x2e\xe0\x17\xe3\xaf\xcb\x2b\xe7\x38\xa5\xec\xd3\x5b\xe4\x0f\x34\x45\xed\x6f\xb3\xe8\xbe\x9b\x00\xc0\x33\x48\x4e\xf3\xdb\xf5\x62\x41\x9f\xc0\x77\x4b\xbe\x96\x25\xf2\x7b\xa9\xc3\xd2\x93\x7f\x86\xac\x78\x44\xfe\x91\x72\x21\x95\x72\x2b\x20\x24\x5f\xa7\x12\x2a\x03\x31\xed\x43\xbc\x36\x1f\x66\x85\xe9\x13\x84\xe4\x94\x2d\x89\x22\x3a\x27\x3e\xe9\x9d\xe0\xbc\x2c\xe4\x7a\xb1\x30\x8f\x6f\xf0\xb1\xaf\xb7\x55\x95\x72\x4c\x24\x02\xc3\x47\x10\xf5\x23\xab\x61\xb1\x66\xe9\x84\x64\xd0\xd1\x1e\x8d\x83\x0c\x61\x9b\x56\x6b\x19\x47\xb9\xe6\x0c\xde\xee\xe3\x93\x2a\xbd\x84\x34\x32\x26\x5f\x9a\x7f\x95\x36\xb9\xaa\x78\xc2\x96\xd8\xc6\xe0\x13\xca\x55\x31\xaf\x23\xc5\xf1\xde\x3e\x30\x71\xfa\x83\x95\x6b\xf9\xb7\x0e\x42\xbf\x04\xe2\xba\x04\x1a\x31\x51\x76\xc4\x3e\xaf\xe5\x7e\x72\x74\x01\x09\x9b\x43\xc0\x0a\x09\xce\x03\xb7\x92\x63\x92\x53\xb6\x0c\x21\x30\x18\x91\x77\x1e\x5d\x28\x65\xbd\x1c\xa4\xf0\xeb\x3e\x4e\xd0\x0e\x75\x75\x1e\xa4\xf2\x09\x5c\x49\xc6\xd7\xf6\x33\x02\x8e\xf7\xe6\xa4\xc6\x70\xa5\x22\x28\x4a\x29\x20\x8e\xe3\x7e\x84\x92\x2c\xb3\xd9\x1e\x42\x30\x0c\xd3\x5d\xa3\xc6\x3d\x8e\x00\x39\x2f\x78\x68\x02\xa7\x6d\xc5\x4c\xa0\x36\x78\x68\xe7\x19\x6c\x3a\x1b\xfc\x9f\xc6\xfd\x46\xa4\xce\x39\x2d\x32\x44\xcb\xe6\x06\xac\xfd\x46\x17\x50\xf0\xb1\x74\x0a\x36\x92\xce\xc8\x80\x2e\x52\x4c\x72\x73\xac\xce\xe8\x34\x4e\x63\xbb\x47\x5b\x11\x99\xef\x37\xf8\xf8\x05\xef\xd7\x28\x64\x90\xc6\xba\xbc\x22\xf0\x87\x6e\x8d\x1b\xeb\xfd\xc8\x14\x6d\xc7\xcc\x4a\x85\xd6\xd2\x38\x8e\x43\xa3\x94\x2e\x8c\xbe\x37\x57\xc0\x68\xe6\x0a\xbe\x29\x79\x46\x33\x03\xc7\x3c\xed\x18\x36\x56\x3a\xa0\x14\xfc\xd8\xbf\x2e\xfe\xcb\x2b\xe7\xbe\xf8\x16\xd9\x3c\xe0\x78\x1f\xbe\x3b\xd4\x30\x64\x73\x17\x89\x83\x3a\x5e\xed\xed\xca\x02\x50\x91\x3e\xbd\x93\xc0\xf5\x99\xa2\xd4\x28\xdf\xf6\x93\xa8\xb2\x8b\x9d\x90\xeb\x94\x3b\x22\xe0\xda\xf2\x48\x2b\xdb\x2b\xce\xdb\x1d\xd2\xac\x98\xa3\x3a\x16\x19\x27\x99\x9e\x7e\x58\x86\xef\x3d\x56\x1b\x6b\xfa\xf3\xd5\x7a\xb7\x3f\xbf\xac\x02\xa2\x2c\x18\xd3\xd5\x47\x3a\xba\xc9\xd6\x21\xc8\xa6\xa9\x3c\xed\xd7\x54\x1a\x54\x21\x7c\xc1\xf4\xe1\x3d\x9b\x5f\x67\x85\xc0\x60\xb2\x2f\x78\xf9\x78\xc8\x3d\x17\xef\xa7\x58\x9f\xf5\x49\x2c\x83\x3c\x24\x9e\x0b\xd1\x55\x1d\x22\xcf\x6c\xd3\xbb\x9c\x2a\xe2\x29\xd2\x6c\x7b\xd3\x6e\x1b\xc6\xd0\x53\xc4\x23\xf5\xd3\xdc\x46\xcf\xce\x3e\x1b\xbd\x17\x5b\x5e\x9b\x6c\x0c\xec\xb3\x83\xa7\xd8\xd5\x5f\x8d\xf5\x18\x35\xb6\x51\x07\xe1\xb0\x75\x6f\x53\x59\xef\x3f\x46\xa9\xee\x1b\x26\x12\x40\x99\x44\xbe\x48\x52\xac\xd4\xb4\xa9\xa6\xd5\xe4\x47\x69\x6d\xe2\xbf\xbf\x56\x2d\xe2\xb4\x56\xd5\x8e\xe1\xfe\x32\x37\x04\xf9\x70\x3c\xee\xeb\x87\xaa\x72\x19\xe6\x90\x0d\xaa\xee\x28\x64\xc6\xee\x1d\x63\x38\xdf\xd6\x62\xdb\x31\x31\xf4\xe3\xc8\x98\xd8\xec\x89\xfa\x88\xcd\x7a\x32\x13\xdf\x5a\x5b\x97\x56\xa7\xc8\x1a\x9e\xef\x5e\x8a\x1c\xcf\xdf\xdd\x07\x7f\x4f\xd8\x3c\x33\x02\x4d\xfb\x1b\xb6\x7c\xb7\xc5\xa0\x18\xa5\xd6\xf0\x6a\xdc\xfa\x80\x91\x60\x33\x61\xb5\x23\x13\x9c\xad\x3b\x59\x5d\x6f\x40\xb8\x57\x48\xab\xae\xcd\xde\x09\xfe\x72\x04\x7d\x21\x5e\xa7\xd1\x77\xc9\xd6\x71\xf4\xc6\xf3\x36\xc8\xcd\x78\xce\x7a\x5e\x33\x03\x4c\xfb\xf7\x7a\x03\x7c\x15\x6f\xc9\x9e\xb8\xe7\xd0\x48\x67\xf6\x34\xe3\x69\xf9\xba\x41\x53\x13\x9e\x90\x0c\xa9\xce\x81\x8a\x8f\xd1\xea\xe8\x48\x07\xc1\x69\xb3\x6a\xf4\x5d\x41\x73\xb9\x41\x1b\xea\x76\xc8\x43\xed\xe7\x78\x6f\xce\x0c\x7b\x53\xfa\xf4\x04\x6b\xe0\xc9\x6e\x83\xd9\x5e\x3c\xe7\x65\x57\x03\x48\x76\xfe\x34\xe4\x2a\x9f\xf2\x72\xd3\xcf\x9b\xc9\x1d\xb6\x8d\xfe\xaa\xdb\xcf\x6b\x1a\x35\x60\x28\xbd\xb6\xae\x0b\xe7\x05\x1c\x69\x03\xff\x26\x45\x3a\x9a\x20\x6d\xea\x98\xe4\x47\x27\x60\x47\xa3\x51\x99\xa4\x29\x47\x53\xa3\x0d\x95\x3b\x99\xd1\x24\x2f\xba\x18\xa3\x1f\xc7\x65\xe5\x74\x36\xee\xc5\x89\x46\xc8\xda\xcb\x31\xf5\xf8\x50\xb7\x3b\x8d\xf2\xa1\xee\x58\x3a\x17\x1f\x6a\xec\xac\x1b\x58\xcb\x84\xbe\xe0\x92\x0a\x89\x7c\x4b\x47\x04\xee\xd6\x45\xcd\x96\x56\x6e\xe1\xa4\x17\x06\xc6\xd3\x3b\xa0\x04\x62\xd0\x05\xcd\x47\x04\x62\xb5\x8d\x85\x0d\xef\x8e\x9c\xa0\x5b\xad\xaf\x8f\x5c\xaa\xb4\x37\x17\xbb\xfb\x75\x9b\xf9\x4e\xee\x3c\x57\x28\xba\x5a\xb6\xdc\xcf\xfe\xb8\xbb\x9c\x97\x91\xd5\xb3\x01\x39\x98\xfe\x9e\x07\xc8\x41\x0c\xe0\x9c\xd7\x6c\x36\x4f\x1a\xd6\x32\x64\x49\x13\xa4\xfb\xc4\x1e\xb1\x24\x0f\x5e\xf5\x6f\x1f\x8f\x6c\x74\xe5\x2d\xb3\xe3\x34\xe5\x6b\x1a\xed\x6b\x7b\xe4\xa7\x01\xf2\xca\xe9\x31\xd9\xe2\x3b\xd7\x9a\x3f\x3c\x59\xa7\x46\xcd\xff\x2d\x34\xab\x9a\x19\xed\x7c\x45\xac\xc4\x4a\x9d\x11\xc8\xa2\xe0\x70\x17\xe9\xc2\x29\x0b\xca\xa4\x86\x65\x87\xf1\xc8\x6f\xba\x1f\xdc\x26\x11\x84\x27\x4d\x9f\x26\x47\x0c\x91\xb9\x82\xa4\x2c\x35\x7d\xd5\xdf\xa2\xf6\x3f\x11\xc4\xff\x50\xb9\xaa\x21\x04\x35\xe0\x30\xfc\xcf\xe6\x88\x63\xb8\xc2\x51\xb9\x40\xc4\x37\xf8\x58\xd3\xc4\xb7\xc3\xe0\x54\x2b\xd5\xfe\xe6\x72\x32\xa7\x90\x9f\xc1\x1b\x06\x08\xf9\x37\x00\x00\xff\xff\x8c\x50\x4b\x50\xf3\x22\x00\x00"), + }, + "/e3t0cmltU3VmZml4ICIucHJvdG8iIC5GaWxlLk5hbWV9fV9taWNyb19odHRwLnBiLmdvLnRtcGw=": &vfsgen۰CompressedFileInfo{ + name: "e3t0cmltU3VmZml4ICIucHJvdG8iIC5GaWxlLk5hbWV9fV9taWNyb19odHRwLnBiLmdvLnRtcGw=", + modTime: time.Date(2021, 2, 19, 13, 55, 46, 337930466, time.UTC), + uncompressedSize: 10502, + + compressedContent: []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x02\xff\xdc\x5a\xdd\x6f\xe3\xb8\x11\x7f\xb6\xfe\x8a\x39\x5d\x6e\x21\x6d\x65\xaa\xc0\xbd\xe5\x90\x87\xed\x36\xdb\x6d\xb1\xc9\x05\x49\xda\x7b\xb8\x1e\x02\xad\x3c\x96\xd5\x48\x94\x42\xd2\x4e\x02\x45\xff\x7b\xc1\x2f\x59\x92\xbf\x63\x7b\xb3\xb8\x3c\xc4\x16\x39\xc3\xf9\xe4\xcc\x8f\x94\xc3\x10\x3e\x16\x23\x84\x04\x29\xb2\x48\xe0\x08\xbe\x3e\x43\xc9\x0a\x51\xc4\xc3\x04\xe9\x30\x4f\x63\x56\x38\x61\x08\xbc\x98\xb2\x18\x4f\xa1\xaa\xc8\xa7\x34\x43\x72\x19\xe5\x58\xd7\x4e\x19\xc5\xf7\x51\x82\x50\x55\x49\x71\x75\x9f\x7c\x89\xb8\x38\xcf\x30\x47\x2a\x40\xd1\xc1\x0b\xf0\x32\x4b\xc5\x07\xc6\xa2\x67\x70\x7f\x71\xe1\x05\xb2\x88\x0b\x78\x01\x86\x65\x16\xc5\x08\x2e\x71\xc1\xbd\x73\xeb\xda\x71\xaa\x6a\x08\x27\x8a\xed\xf4\xcc\xf0\xd7\xb5\x1e\xbd\x41\x36\x4b\x63\x94\x62\xd5\xa4\x79\x56\x7a\xc0\x0b\x08\x96\xe6\x37\xd3\xf1\x38\x7d\x02\xd7\x4c\xb9\xd0\x2c\x89\x8c\xe5\x3c\x91\x7c\x59\xca\x85\x5e\x93\x45\x34\xc1\xf9\x3a\x17\x28\x26\xc5\xc8\x48\x4b\xc7\x40\x0b\x01\x5e\x5c\x50\x11\xa5\x94\x83\xf7\x3f\x5e\x50\xf0\x8a\x12\x69\x54\xa6\xbf\x96\x22\x2d\x28\x10\xdf\x07\x97\x4e\xb3\xcc\xf5\x61\xce\xb8\x40\x44\xae\x91\x97\x05\xe5\xc8\x35\x15\x68\xc9\x27\xf7\x01\x9c\xcc\xa4\x4e\x1b\x39\x86\x70\x92\xf3\x44\x3c\x97\xca\x74\x2f\x41\x71\x81\x9c\x47\x09\xde\xca\x21\xed\xb0\x93\x19\xb9\x89\x27\x98\x47\xe4\x5f\xbc\xa0\xe6\xeb\x35\x8e\x1b\xd5\xac\x13\xce\x20\x2a\x4b\xa4\xa3\x66\xc0\xae\xad\x5d\x69\xa8\x25\xc1\x36\x5f\x9d\x34\x2f\x0b\x26\xc0\x73\x06\xae\xf4\x16\x3e\x09\xb7\x71\x21\x82\x97\x21\x4d\x26\xc2\xca\xf2\xe1\xaf\x92\x09\xc0\x1d\xe7\x86\xce\xac\x13\x86\x00\x2e\x45\x11\x4e\x84\x28\x5d\xc7\x19\xa8\xc4\xbb\x8b\xb3\x54\xa6\x92\x9b\xa4\x62\x32\xfd\x4a\xe2\x22\x0f\xa7\x34\xe5\x22\x8a\xef\x87\x05\x4b\x42\x45\x15\xce\x7e\x0e\x35\xa1\x0b\x96\x91\x23\x9b\x21\xdb\x82\x51\x13\xba\x96\x2f\x2a\xd3\x2d\x98\xa2\x32\x75\xbb\x2a\xde\x49\xbd\x37\x70\x0e\x35\xe9\x50\x92\x86\xb3\x9f\x5d\xc7\x77\x9c\x59\xc4\xc0\x73\x00\x00\xee\xa0\xad\x39\xd1\xc9\xd0\x99\xd1\xec\x76\xc6\x77\x1c\x95\x11\x55\xd5\xd9\x1b\x2f\x90\x15\x8f\xc8\x3e\xa5\x8c\x8b\xba\x36\x33\xc0\x05\x9b\xc6\x02\x2a\xb5\x5e\xdc\x5d\xef\xa3\xfa\x50\x33\x54\xae\xc0\x05\x4b\x69\xe2\xd4\x8e\x0c\xca\x85\xa4\x04\x13\x06\x2e\xa6\xe3\xb1\x1a\xbe\xc4\xc7\xae\xdc\xb9\xa8\x98\x61\x24\x10\x28\x3e\x02\xb7\x43\x5a\xc2\x78\x4a\xe3\x35\x9c\x5e\x4b\x7a\xb0\x5c\x49\x1f\x56\x49\xd5\x96\x31\x14\x53\x46\xe1\xdd\x36\x3e\xa9\xe2\x53\x88\x03\x65\xf2\xa9\xfa\x5f\x3b\xaa\x5c\xac\xab\x0b\x27\x0c\x1f\xf4\x80\xaa\x41\xff\xa4\xe5\x54\xa8\x3d\xd8\xad\x72\xc4\x56\xb9\x86\x8d\x97\x2d\xb6\x5f\xa7\x62\x1b\x3e\xb9\x85\x22\x3a\x02\x4f\x96\x22\xe3\x80\x1b\xc1\x30\xca\x53\x9a\xf8\xe0\x29\x15\x91\xb5\x86\xea\x5a\xfb\xd8\x8b\xe1\xfd\x36\x2e\x90\xee\x34\x85\xdc\x8b\xc5\x13\x98\x0d\x4c\x3e\xea\xcf\x00\x18\x3e\xa8\x95\x1a\xb3\xeb\x3a\x80\xa2\x14\x1c\x08\x21\xdd\xf8\x44\x59\xa6\x13\xd3\x07\xaf\x1f\xa4\xbb\x46\x8c\x19\x0e\x00\x19\x2b\x98\xaf\xc2\x56\x55\x80\x19\x47\x69\x6e\xdf\xca\xc3\x5b\x74\x2c\xe5\xbf\x17\xd7\x2b\x16\x9b\x6d\x92\xa5\xa3\x6b\x53\x6e\xe5\x66\x79\x75\xa3\x6b\x31\x6f\x68\x5d\x92\x52\x56\xfe\xa8\x94\x89\x9f\x47\xf7\xe8\xe5\x51\xf9\xbb\xde\xe3\x7f\xa4\x54\x20\x1b\x47\x31\x56\x75\x20\x1d\x99\x21\x5d\xb7\x60\x5d\xfb\x8d\xe8\x1d\x5b\xe8\x5c\x8f\xdf\xdd\xaa\x3a\xb9\xaf\x6b\xf7\x0f\x38\x93\x75\x62\xb8\x6b\x3b\xb5\x5d\xb2\x9a\xfb\xa1\xe7\xd3\xce\x63\xfb\x89\xaa\xf0\x9d\xda\x06\xec\xc9\xc7\x40\xcd\x00\x2c\xf4\x12\x53\x78\x3c\xb7\xaa\xe4\xe3\x7f\x90\x7d\x05\x52\xd7\xae\x1f\xc0\x4a\x96\xab\x48\x4c\x2c\x83\xfc\x6e\x18\x0c\xfd\xf2\x78\x4b\xda\xbf\x15\xa3\x67\x20\x3e\xb8\xff\x38\xbf\x9d\x87\x78\x99\x04\x49\x69\x25\x68\xae\xbe\x84\x96\xbd\x7b\xa6\xd8\x2e\x49\xb6\x4c\xd7\x73\x99\xf9\x17\x51\xe9\xe9\xc8\xaf\xd7\xb2\x35\xe0\x3b\x8d\xe4\x82\x2d\x2b\xb3\xde\x42\x31\x36\x9c\x5c\x0d\xa8\x3d\x27\xc3\x1c\x93\x98\x68\x1a\xb9\xc5\x03\xf5\x7c\x89\x8f\xd7\xf8\x30\x45\x2e\xbc\x98\xc8\xae\x13\x80\xdb\xaf\x38\xa4\x29\x0d\x6e\xa0\x7a\x59\xab\x06\x54\xb5\x1f\xe8\x44\x22\x84\xe8\xfd\x90\x8e\x95\xc0\x1f\xce\x80\xa6\x99\x69\x84\x4d\x2b\xa4\x69\xa6\xf4\x51\xa3\xb5\xd3\x09\xc9\x92\x6a\x0b\xdf\xf6\xaf\xad\xff\xe9\x99\xf1\x1f\xb9\x91\x9b\x83\xe1\x83\xff\xcb\xae\x86\x21\x1d\x99\x50\xec\x84\x04\xac\xbb\x2b\xad\x40\x1d\xc8\xd5\xed\x92\x19\x47\xbb\x26\x57\x65\xec\x5d\xb7\xc4\x56\x4d\x79\xb1\x31\x97\x05\x79\x8f\x88\x4b\xcb\x03\x29\x6c\xbb\x40\xaf\xf6\x48\x33\xa3\xd7\x9a\x9b\xa4\xbc\xa4\xc0\xce\x6e\x39\xbe\x35\xde\x6c\xcc\xe9\x02\x4f\xed\xde\x2e\xb0\xd3\x02\x9c\x5a\x2b\xa3\xf0\xce\x12\xac\xa3\xd2\xb5\xaf\x64\xd3\x73\x9f\xb6\xeb\xb9\x8d\x56\x3e\x5c\x63\x3c\xfb\x40\x47\x1f\xb3\x82\xa3\xb7\xb6\x6d\x0e\xf2\xe5\x31\x1f\x98\x80\x3f\x11\xb9\xd6\x05\x4f\xbc\xdc\x77\x06\x26\x44\x67\x36\x44\x03\x45\x26\xa9\x8c\x28\x67\x50\x3b\x0d\xd9\x0f\x73\xb2\x7e\x0c\x07\xb5\x33\x70\xec\x68\xae\xa3\xd7\x1c\xbc\xe4\xb9\xeb\xb5\x96\x5b\x93\x95\x81\x5d\xd8\xfc\x44\xcc\x06\xb4\xba\xee\x23\x46\xe3\x18\xcf\xef\x23\x9b\x55\x22\x2d\xfd\x3e\x42\x65\xe1\x50\x91\x80\x16\xb4\x58\x6f\xaa\xaa\x35\xf9\x5e\x52\x9b\xf8\x6f\x2f\x55\xb2\x18\xa9\x1a\xe7\x2f\x94\xe2\xe1\x1e\xc9\xad\x6d\xea\xa3\xc7\x6d\xfd\xd0\xca\x31\xa3\x5b\x6f\xdf\xed\xa5\x9b\xb2\x7c\x03\x4e\xcd\x57\x55\xd9\x79\xa7\xe8\x7b\x72\x49\xa7\x58\xac\x8a\x72\x89\x15\x3b\xaa\xb9\x2a\xd2\x96\x57\x95\xf1\x40\x73\x02\x36\xf7\x09\xe6\x04\xbc\xb9\x10\x7e\x8e\xe8\x28\x53\x0c\x4d\xfd\xeb\x17\x7d\x43\xe2\xac\xbc\x8c\x82\xb7\x38\x75\xee\x8a\x7b\x74\x22\x4c\x36\x24\x82\xb1\x75\xe3\xa9\xa7\xd3\x21\xcc\x4d\x88\x16\x37\x4f\xdf\x35\x08\x66\x0f\x00\xe3\x0c\x5a\x95\xbe\x8d\xb7\xf6\x03\x38\x83\xc1\x02\xbc\x59\x9e\xb2\x83\x41\xd3\x04\x54\xfd\x1f\x74\x3a\xf8\x84\xac\xc8\x1e\xd2\x71\x68\x20\x13\x7b\x3d\xe6\x99\x9f\x66\x95\x36\x16\xf2\xf8\x4e\x1f\xec\xec\x28\x78\x1f\xa9\x06\x8f\xb4\x34\x38\x6c\x56\x2d\x3d\x4b\x4b\x34\xd7\xab\x42\xed\x12\xb9\xab\xfd\x0c\x1f\xd4\x9a\xbd\x12\x1a\xbe\xdf\xd5\x16\xb5\xed\x3e\xdf\xde\x5e\x79\x8f\xa0\xce\x31\xf6\xb0\xf3\x1b\x4b\x05\xb2\x00\x18\xbc\x37\xe3\x0a\x55\xea\x9a\x39\xce\x05\xb9\x62\x29\x15\x63\xcf\xa5\xf8\x28\xd5\x91\x93\xa7\xf0\xd3\x8f\x7f\x99\xfd\x97\x4a\x58\x29\x41\x64\x18\xc2\xe7\x0f\x97\x7f\xff\x72\x0e\x1f\xbe\x7c\x81\x9b\xdb\x7f\x7f\xfa\xe4\xd4\xce\xfb\xf0\x18\x58\xb0\x17\xf3\x76\x29\x5c\xbd\xcd\x8f\x0b\x04\x7b\x2a\xe9\x56\xd9\xe0\xc0\x7c\x5d\x3e\x34\x8d\xa7\x01\x19\xfe\xbc\x23\x9d\xb5\x1b\x8f\x45\x7c\x3d\x30\xd5\xe9\x3f\x72\x8b\xbf\x02\xce\x2d\xe8\xbf\x88\xe6\xf6\xc6\x72\x8b\x32\xd6\x42\xb9\x03\x00\xb9\xa5\x51\x59\x8b\xa8\xf6\x46\x71\x0b\x22\x37\x82\xb8\xd5\x10\x4e\xe5\x6b\x3f\x27\xf7\x4b\xc9\xf5\xa9\xb8\x0e\xbb\x35\xc8\x6d\x09\xa8\x7c\xbd\x4e\x1d\xd4\xd6\x2e\xa2\x4b\x51\x5b\xbb\x7b\x1e\x0b\xb5\x35\x76\xf6\x00\x9b\x85\x52\xad\xab\x41\xfb\x9e\xeb\x05\xa6\x34\x7d\xf0\xcd\xdb\x26\x75\x3b\x04\xb9\xc6\x47\xa2\x00\x1e\x89\x94\x8f\x9f\x8d\x9b\x9b\x24\x30\x1e\x43\xe9\xb1\xa1\x5c\x51\x86\x42\xf1\x7a\xbe\x79\x57\xd1\xd5\x5c\x16\xe2\x9b\xd2\x54\xe2\x9f\x7e\x9c\xb9\x01\xa0\xdf\x03\x9a\x61\x08\xd7\x98\xa4\x5c\x20\x5b\xd1\x5d\x80\x99\x79\x6e\x91\xe7\xc4\x4c\x1c\xea\xe6\x45\xd9\xb5\x41\x0b\x8f\xf7\x4a\xb4\xfa\x08\x80\x4f\x56\x81\xd9\xfe\x15\xb5\x61\x34\xb3\xf6\x96\xba\x7d\x10\xd9\xdc\x47\xe6\xc1\x80\xea\x38\x37\x50\xf3\x1b\xe5\x85\xd7\x3e\xdf\xe4\x16\xec\x75\x20\xff\x18\x3a\xec\x7c\x62\x38\xb8\x0e\x3b\xa1\x90\x23\xdd\x48\xea\x9c\x68\xe0\x5d\x1f\x4e\xae\x39\x9d\x1c\xce\x0f\x1a\x08\xc3\x5b\xfd\x6d\xe3\x87\x85\x6e\xb0\xa2\x67\xed\xbd\x37\x55\x6d\x7f\x43\x3f\xbc\xb5\x0e\x61\x68\xbf\xce\x0f\x07\x4b\x8f\x06\xdd\x83\x81\xbe\x08\x86\x37\xfd\x5b\x55\xe3\x5b\x57\xc3\xdf\x32\x97\xd7\xb5\x99\xe3\xeb\xf0\x3d\xc4\x62\x62\x61\xda\xc6\xa3\x68\xc5\x27\xf5\x71\x74\x18\x17\x0c\xee\x02\xb9\xa5\xca\x22\xa5\x42\x6a\xa4\xdb\xef\x92\x1f\x87\x9c\x1b\x22\xee\xf9\x87\x4a\x95\x26\x1f\x14\x56\xe9\xbe\x8e\x85\xe6\x67\x40\xe4\xb7\x54\x4c\xac\x74\xcf\xea\xea\xfb\x7f\xb2\x7c\x30\xb0\x95\x1b\x8c\xe6\x71\x72\x89\x8f\x16\xff\xbd\xeb\x47\xa3\x9a\x98\x5f\x21\x10\x42\x0e\xe2\x0a\xe7\x8d\x7d\xa0\x74\x70\xfe\x1f\x00\x00\xff\xff\xfb\x15\xb7\xac\x06\x29\x00\x00"), + }, + "/e3t0cmltU3VmZml4ICIucHJvdG8iIC5GaWxlLk5hbWV9fV9taWNyby5wYi5nby50bXBs": &vfsgen۰CompressedFileInfo{ + name: "e3t0cmltU3VmZml4ICIucHJvdG8iIC5GaWxlLk5hbWV9fV9taWNyby5wYi5nby50bXBs", + modTime: time.Date(2021, 2, 2, 14, 50, 50, 937560688, time.UTC), + uncompressedSize: 4594, + + compressedContent: []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x02\xff\xd4\x57\x5d\x6b\xe4\x36\x14\x7d\x8e\x7f\xc5\x45\x84\x62\x2f\x13\xcf\x96\xbe\x4d\x99\x87\x6c\xd8\xd2\x42\xb3\xbb\x34\xa5\x2f\xcb\x12\x14\xeb\x8e\xa3\xc6\x96\x5c\x59\x4e\x13\x1c\xfd\xf7\x22\x5b\xfe\x52\x3c\xce\x4c\x08\x0b\x9d\x97\x58\xd2\x3d\x57\xd7\xf7\x1c\x1d\x2b\xeb\x35\x5c\x48\x86\x90\xa2\x40\x45\x35\x32\xb8\x79\x84\x42\x49\x2d\x93\xb3\x14\xc5\x59\xce\x13\x25\x83\xf5\x1a\x4a\x59\xa9\x04\x37\x50\xd7\xf1\x2f\x3c\xc3\xf8\x13\xcd\xd1\x98\xa0\xa0\xc9\x1d\x4d\x11\xea\x3a\x95\x5f\xee\xd2\xdf\x69\xa9\x3f\x66\x98\xa3\xd0\xd0\xc4\xc1\x13\x94\x45\xc6\xf5\xb9\x52\xf4\x11\xc8\xcf\x04\x9e\x20\xa3\xa5\x86\x27\x50\x58\x64\x34\x41\x20\x31\x01\x72\x4d\x8c\x09\x02\x9e\x17\x52\x69\x08\x83\x13\x92\x48\xa1\xf1\x41\x93\x20\x38\x69\x6a\xb8\xa6\x05\x07\x92\x72\x7d\x5b\xdd\xc4\x89\xcc\xd7\x95\xe0\xa5\xa6\xc9\xdd\x99\x54\xe9\xba\x09\x59\xdf\xff\xb4\xa6\x05\x27\x00\x00\x1d\x2a\xc9\xb8\xad\xe5\x65\x60\x1b\x48\x20\x88\x82\xa0\xae\xcf\xe0\xf4\x0a\xd5\x3d\x4f\xd0\xbe\x27\x6c\xb6\x10\xbb\x71\xf3\xe2\xf0\x04\x5a\xf1\xfc\xaa\xda\xed\xf8\x03\x10\xb7\x44\xc0\x98\x16\x8b\x85\xa8\x72\x8b\x7a\xdf\x4d\x29\x2a\x52\x1c\x92\x5c\xa2\xbe\x95\xcc\xad\xf1\x1d\x08\xa9\x21\xb4\xaf\x4c\xb9\x28\x21\xfc\xbb\x94\x02\xc2\x5b\xad\x8b\xcf\x85\xe6\x52\x40\x1c\x45\x40\x44\x95\x65\x24\x82\x11\x0a\xdb\xa0\xbf\x50\xdd\x40\x1c\x01\xf1\x2b\xd8\x02\x65\xac\x1b\xfc\x38\xad\xc5\x02\xbf\x50\x7d\x5b\x9e\x33\xc6\xed\x26\x34\xfb\xc0\x05\xe3\x22\x2d\x21\x3e\x28\x0f\x0a\x76\xd0\xa3\x95\xcf\x27\xfc\xb7\xae\xc7\x3d\x35\xe6\xa3\x60\x85\xe4\x42\x97\x56\x6f\xf7\x9c\x61\x09\x96\x63\xec\xa7\x73\xd4\x8c\x6a\x0a\x3b\xa9\xc0\x07\x43\xd9\x8e\x82\x5d\x25\x92\xc5\xec\x61\x04\x5f\xbf\xbd\xeb\x35\x14\x77\x0b\x50\x07\x56\x28\xc3\x76\x9b\x2d\xe4\xf4\x0e\xc3\xd9\xe8\x15\xbc\x5f\x41\x5d\x77\x3d\x30\x26\x6a\xd0\x03\x11\x6e\xa1\x21\xdc\xae\xdc\x53\xd5\xe7\x86\x99\x84\x3d\xdc\x35\xa9\x1b\xee\x13\xca\x78\xb7\xe3\xc4\xd2\x21\x4f\x47\x21\x9b\xad\x87\x00\x6f\x0b\x1c\x87\xbb\x2a\x9c\xbe\xc6\x5d\x83\x2d\xfc\xf0\xfc\xdd\xda\xce\xda\x9f\xe5\x62\x03\xc4\x27\x27\xae\x6b\x67\x20\x64\xd5\xc7\x5a\x31\x6e\xe0\xeb\xb7\x52\x2b\x2e\xd2\xda\x82\x46\x25\xd8\x55\x63\x88\x19\xe2\xdb\xa2\xf6\x23\xba\xd6\x8d\x31\x1f\x24\x7b\x6c\xeb\x19\x05\xda\xc9\x49\x25\xae\x09\x52\x41\x18\x5f\x34\xbe\x70\xa5\x15\xd2\x9c\x8b\x34\x82\xb0\xe1\x06\xd5\x30\xe5\x7a\x62\x7f\xed\xe4\x06\xb4\xaa\x70\x9a\x0f\x05\x1b\xc5\xfd\x4a\x05\xcb\x50\x6d\x80\xa8\x22\x71\x3b\x1b\x4f\x8f\x5b\xa0\x45\x81\x82\x85\xfd\xd4\xaa\x5f\x8d\x3c\xbd\x9c\x72\xc1\xf0\x61\x05\xa7\xe8\xcc\x77\xb3\x9d\x10\x38\x9c\xf1\xef\xcc\xa0\xab\xe7\x50\xfa\xba\xf0\x65\xee\xba\xa8\xff\x35\x71\x43\xde\xc3\x47\x0a\x75\xa5\xc4\xb0\x55\xd0\x9a\xab\x4f\x8e\x1b\x00\x17\x1a\xd5\x8e\x26\x18\xe8\xc7\x02\x5f\x0e\x6b\x2c\x71\xd9\x84\x1a\x23\x51\xf8\x8f\x73\x04\xfb\x61\xfc\x4d\x14\x95\xfe\xd3\x6e\x30\xfd\xd6\xc7\xfd\xb7\x7e\x84\x2c\x8b\x11\xf2\x73\xa5\x0f\x86\x76\xb4\xfa\x1c\xce\x30\x3d\xc6\x50\xc1\x66\x41\xd6\x43\xe7\x81\x16\xea\xa4\x1d\xba\x4b\x48\x7c\xd1\xfe\x5d\xc1\xbb\xba\x1e\xde\xde\x98\x15\xc4\x71\x3c\xbe\x68\xc4\x17\x34\xcb\xda\x33\x17\x41\xe8\x37\xfc\xba\xcf\xec\xa6\x57\x80\x4a\x49\x15\xb9\x7a\x31\x2b\xf1\xe5\x1a\xde\x76\x4b\x31\xf0\x7a\xd8\xf6\xc7\xb5\xa0\x89\xee\x48\xb7\xd1\xfb\x77\x6f\x9e\x8d\xbd\x7d\x2d\x5d\x96\x8e\x15\x5f\x0f\x3b\x52\x79\x0d\xee\x38\xd1\xcd\x1e\xb2\x67\x04\x78\xc7\x0d\xc0\x75\x36\x8c\xc0\xeb\x75\xb3\x7a\x85\x82\x5d\x96\x69\xd8\xa3\x6a\x13\xb5\x4d\x6c\x96\xff\xc0\xe4\x7e\x61\x79\x72\x0a\x9e\x3b\x62\x73\x0a\xf6\xb8\xa2\xcd\x7c\x2e\xd8\x45\x26\x4b\x0c\x17\x99\xf4\x5d\xaa\x83\x3c\x2b\xc3\xaf\xc0\xc5\xdb\x57\x0c\x3d\x59\xf9\xe8\xa9\x23\xda\x5c\x5e\xd9\xa3\xaa\x0f\xaf\xb6\xbf\xa6\x9a\xf1\xd3\x7a\x0d\x97\x56\xd0\xcd\x1d\x13\x15\x94\xba\xda\xed\x66\x8d\xd6\x7d\x0d\xba\xc0\xdb\x76\x38\x2f\x84\x2e\x76\x4c\xff\xc9\x4b\xff\x1a\x7c\x57\xb5\x1f\x6f\xb2\x93\x2b\xe9\x1e\x76\x8f\xb1\x92\x85\xc3\xd3\x64\x7d\xa6\x8a\x83\x1c\xeb\xe8\xac\x83\x1e\x5e\xe7\x88\x9e\xf8\xba\xfc\x73\x5a\x33\x41\xf0\xf6\x1a\x68\xaf\x2a\xaf\x55\x42\x07\x7e\x5b\xf3\x6b\x62\x3d\xef\x5b\x72\xbe\x45\xdf\x5b\x74\xbd\x57\x7b\x9e\xdd\xb2\x77\xbc\x3d\x1c\x4e\xdd\xc8\x77\xba\x25\x6f\x1a\x5c\xee\xa5\xac\x4b\x6e\x39\xf1\xb7\xb1\xe6\x66\xbe\xab\xf3\xee\xf6\x5f\x00\x00\x00\xff\xff\x35\xbb\xe5\x6c\xf2\x11\x00\x00"), + }, + } + fs["/"].(*vfsgen۰DirInfo).entries = []os.FileInfo{ + fs["/e3suU2VydmljZS5OYW1lIHwgdHJpbVN1ZmZpeCAiU2VydmljZSIgfCBsb3dlcn19X21pY3JvX2NoaS5wYi5nby50bXBs"].(os.FileInfo), + fs["/e3suU2VydmljZS5OYW1lIHwgdHJpbVN1ZmZpeCAiU2VydmljZSIgfCBsb3dlcn19X21pY3JvX2dvcmlsbGEucGIuZ28udG1wbA=="].(os.FileInfo), + fs["/e3t0cmltU3VmZml4ICIucHJvdG8iIC5GaWxlLk5hbWV9fV9taWNyb19ncnBjLnBiLmdvLnRtcGw="].(os.FileInfo), + fs["/e3t0cmltU3VmZml4ICIucHJvdG8iIC5GaWxlLk5hbWV9fV9taWNyb19odHRwLnBiLmdvLnRtcGw="].(os.FileInfo), + fs["/e3t0cmltU3VmZml4ICIucHJvdG8iIC5GaWxlLk5hbWV9fV9taWNyby5wYi5nby50bXBs"].(os.FileInfo), + } + + return fs +}() + +type vfsgen۰FS map[string]interface{} + +func (fs vfsgen۰FS) Open(path string) (http.File, error) { + path = pathpkg.Clean("/" + path) + f, ok := fs[path] + if !ok { + return nil, &os.PathError{Op: "open", Path: path, Err: os.ErrNotExist} + } + + switch f := f.(type) { + case *vfsgen۰CompressedFileInfo: + gr, err := gzip.NewReader(bytes.NewReader(f.compressedContent)) + if err != nil { + // This should never happen because we generate the gzip bytes such that they are always valid. + panic("unexpected error reading own gzip compressed bytes: " + err.Error()) + } + return &vfsgen۰CompressedFile{ + vfsgen۰CompressedFileInfo: f, + gr: gr, + }, nil + case *vfsgen۰DirInfo: + return &vfsgen۰Dir{ + vfsgen۰DirInfo: f, + }, nil + default: + // This should never happen because we generate only the above types. + panic(fmt.Sprintf("unexpected type %T", f)) + } +} + +// vfsgen۰CompressedFileInfo is a static definition of a gzip compressed file. +type vfsgen۰CompressedFileInfo struct { + name string + modTime time.Time + compressedContent []byte + uncompressedSize int64 +} + +func (f *vfsgen۰CompressedFileInfo) Readdir(count int) ([]os.FileInfo, error) { + return nil, fmt.Errorf("cannot Readdir from file %s", f.name) +} +func (f *vfsgen۰CompressedFileInfo) Stat() (os.FileInfo, error) { return f, nil } + +func (f *vfsgen۰CompressedFileInfo) GzipBytes() []byte { + return f.compressedContent +} + +func (f *vfsgen۰CompressedFileInfo) Name() string { return f.name } +func (f *vfsgen۰CompressedFileInfo) Size() int64 { return f.uncompressedSize } +func (f *vfsgen۰CompressedFileInfo) Mode() os.FileMode { return 0444 } +func (f *vfsgen۰CompressedFileInfo) ModTime() time.Time { return f.modTime } +func (f *vfsgen۰CompressedFileInfo) IsDir() bool { return false } +func (f *vfsgen۰CompressedFileInfo) Sys() interface{} { return nil } + +// vfsgen۰CompressedFile is an opened compressedFile instance. +type vfsgen۰CompressedFile struct { + *vfsgen۰CompressedFileInfo + gr *gzip.Reader + grPos int64 // Actual gr uncompressed position. + seekPos int64 // Seek uncompressed position. +} + +func (f *vfsgen۰CompressedFile) Read(p []byte) (n int, err error) { + if f.grPos > f.seekPos { + // Rewind to beginning. + err = f.gr.Reset(bytes.NewReader(f.compressedContent)) + if err != nil { + return 0, err + } + f.grPos = 0 + } + if f.grPos < f.seekPos { + // Fast-forward. + _, err = io.CopyN(ioutil.Discard, f.gr, f.seekPos-f.grPos) + if err != nil { + return 0, err + } + f.grPos = f.seekPos + } + n, err = f.gr.Read(p) + f.grPos += int64(n) + f.seekPos = f.grPos + return n, err +} +func (f *vfsgen۰CompressedFile) Seek(offset int64, whence int) (int64, error) { + switch whence { + case io.SeekStart: + f.seekPos = 0 + offset + case io.SeekCurrent: + f.seekPos += offset + case io.SeekEnd: + f.seekPos = f.uncompressedSize + offset + default: + panic(fmt.Errorf("invalid whence value: %v", whence)) + } + return f.seekPos, nil +} +func (f *vfsgen۰CompressedFile) Close() error { + return f.gr.Close() +} + +// vfsgen۰DirInfo is a static definition of a directory. +type vfsgen۰DirInfo struct { + name string + modTime time.Time + entries []os.FileInfo +} + +func (d *vfsgen۰DirInfo) Read([]byte) (int, error) { + return 0, fmt.Errorf("cannot Read from directory %s", d.name) +} +func (d *vfsgen۰DirInfo) Close() error { return nil } +func (d *vfsgen۰DirInfo) Stat() (os.FileInfo, error) { return d, nil } + +func (d *vfsgen۰DirInfo) Name() string { return d.name } +func (d *vfsgen۰DirInfo) Size() int64 { return 0 } +func (d *vfsgen۰DirInfo) Mode() os.FileMode { return 0755 | os.ModeDir } +func (d *vfsgen۰DirInfo) ModTime() time.Time { return d.modTime } +func (d *vfsgen۰DirInfo) IsDir() bool { return true } +func (d *vfsgen۰DirInfo) Sys() interface{} { return nil } + +// vfsgen۰Dir is an opened dir instance. +type vfsgen۰Dir struct { + *vfsgen۰DirInfo + pos int // Position within entries for Seek and Readdir. +} + +func (d *vfsgen۰Dir) Seek(offset int64, whence int) (int64, error) { + if offset == 0 && whence == io.SeekStart { + d.pos = 0 + return 0, nil + } + return 0, fmt.Errorf("unsupported Seek in directory %s", d.name) +} + +func (d *vfsgen۰Dir) Readdir(count int) ([]os.FileInfo, error) { + if d.pos >= len(d.entries) && count > 0 { + return nil, io.EOF + } + if count <= 0 || count > len(d.entries)-d.pos { + count = len(d.entries) - d.pos + } + e := d.entries[d.pos : d.pos+count] + d.pos += count + return e, nil +} diff --git a/ast.go b/ast.go deleted file mode 100644 index 6977741..0000000 --- a/ast.go +++ /dev/null @@ -1,170 +0,0 @@ -package main - -import ( - "go/ast" - "go/format" - "go/parser" - "go/token" - "os" - "path/filepath" - "strings" - - "github.com/fatih/structtag" - tag_options "go.unistack.org/micro-proto/v4/tag" - "google.golang.org/protobuf/compiler/protogen" - "google.golang.org/protobuf/proto" -) - -var astFields = make(map[string]map[string]map[string]*structtag.Tags) // map proto file with proto message ast struct - -func (g *Generator) astFill(file *protogen.File, message *protogen.Message) error { - for _, field := range message.Fields { - if field.Desc.Options() == nil { - continue - } - if !proto.HasExtension(field.Desc.Options(), tag_options.E_Tags) { - continue - } - - opts := proto.GetExtension(field.Desc.Options(), tag_options.E_Tags) - if opts != nil { - fpath := filepath.Join(g.tagPath, file.GeneratedFilenamePrefix+".pb.go") - mp, ok := astFields[fpath] - if !ok { - mp = make(map[string]map[string]*structtag.Tags) - } - nmp, ok := mp[message.GoIdent.GoName] - if !ok { - nmp = make(map[string]*structtag.Tags) - } - tags, err := structtag.Parse(opts.(string)) - if err != nil { - return err - } - nmp[field.GoName] = tags - mp[message.GoIdent.GoName] = nmp - astFields[fpath] = mp - } - } - for _, nmessage := range message.Messages { - if err := g.astFill(file, nmessage); err != nil { - return err - } - } - - return nil -} - -func (g *Generator) astGenerate(plugin *protogen.Plugin) error { - if g.tagPath == "" { - return nil - } - - for _, file := range plugin.Files { - if !file.Generate { - continue - } - for _, message := range file.Messages { - if err := g.astFill(file, message); err != nil { - return err - } - } - } - - for file, mp := range astFields { - fset := token.NewFileSet() - pf, err := parser.ParseFile(fset, file, nil, parser.AllErrors|parser.ParseComments) - if err != nil { - return err - } - - r := retag{} - f := func(n ast.Node) ast.Visitor { - if r.err != nil { - return nil - } - - if v, ok := n.(*ast.TypeSpec); ok { - r.fields = mp[v.Name.Name] - return r - } - - return nil - } - - ast.Walk(structVisitor{f}, pf) - - if r.err != nil { - return err - } - - fp, err := os.OpenFile(file, os.O_WRONLY|os.O_TRUNC, os.FileMode(0644)) - if err != nil { - return err - } - if err = format.Node(fp, fset, pf); err != nil { - fp.Close() - return err - } - if err = fp.Close(); err != nil { - return err - } - } - - return nil -} - -type retag struct { - err error - fields map[string]*structtag.Tags -} - -func (v retag) Visit(n ast.Node) ast.Visitor { - if v.err != nil { - return nil - } - if f, ok := n.(*ast.Field); ok { - if len(f.Names) == 0 { - return nil - } - - newTags := v.fields[f.Names[0].String()] - if newTags == nil { - return nil - } - if f.Tag == nil { - f.Tag = &ast.BasicLit{ - Kind: token.STRING, - } - } - - oldTags, err := structtag.Parse(strings.Trim(f.Tag.Value, "`")) - if err != nil { - v.err = err - return nil - } - for _, t := range newTags.Tags() { - oldTags.Set(t) - } - - f.Tag.Value = "`" + oldTags.String() + "`" - - return nil - } - - return v -} - -type structVisitor struct { - visitor func(n ast.Node) ast.Visitor -} - -func (v structVisitor) Visit(n ast.Node) ast.Visitor { - if tp, ok := n.(*ast.TypeSpec); ok { - if _, ok := tp.Type.(*ast.StructType); ok { - ast.Walk(v.visitor(n), n) - return nil // This will ensure this struct is no longer traversed - } - } - return v -} diff --git a/chi.go b/chi.go deleted file mode 100644 index 464a135..0000000 --- a/chi.go +++ /dev/null @@ -1,78 +0,0 @@ -package main - -import ( - "google.golang.org/protobuf/compiler/protogen" -) - -var chiPackageFiles map[protogen.GoPackageName]struct{} - -func (g *Generator) chiGenerate(component string, plugin *protogen.Plugin) error { - chiPackageFiles = make(map[protogen.GoPackageName]struct{}) - for _, file := range plugin.Files { - if !file.Generate { - continue - } - if len(file.Services) == 0 { - continue - } - if _, ok := chiPackageFiles[file.GoPackageName]; ok { - continue - } - - chiPackageFiles[file.GoPackageName] = struct{}{} - gname := "micro" + "_" + component + ".pb.go" - - path := file.GoImportPath - if g.standalone { - path = "." - } - gfile := plugin.NewGeneratedFile(gname, path) - - gfile.P("// Code generated by protoc-gen-go-micro. DO NOT EDIT.") - gfile.P("// protoc-gen-go-micro version: " + versionComment) - gfile.P() - gfile.P("package ", file.GoPackageName) - gfile.P() - - gfile.Import(contextPackage) - gfile.Import(fmtPackage) - gfile.Import(httpPackage) - gfile.Import(reflectPackage) - gfile.Import(stringsPackage) - gfile.Import(chiPackage) - gfile.Import(chiMiddlewarePackage) - - gfile.P("type routeKey struct{}") - - gfile.P("func RouteName(ctx ", contextPackage.Ident("Context"), ") (string, bool) {") - gfile.P("value, ok := ctx.Value(routeKey{}).(string)") - gfile.P("return value, ok") - gfile.P("}") - gfile.P() - gfile.P("func RegisterHandlers(r *", chiPackage.Ident("Mux"), ", h interface{}, eps []", microServerHttpPackage.Ident("EndpointMetadata"), ") error {") - gfile.P("v := ", reflectPackage.Ident("ValueOf"), "(h)") - gfile.P("if v.NumMethod() < 1 {") - gfile.P(`return `, fmtPackage.Ident("Errorf"), `("handler has no methods: %T", h)`) - gfile.P("}") - gfile.P("for _, ep := range eps {") - gfile.P(`idx := `, stringsPackage.Ident("Index"), `(ep.Name, ".")`) - gfile.P(`if idx < 1 || len(ep.Name) <= idx {`) - gfile.P(`return `, fmtPackage.Ident("Errorf"), `("invalid endpoint name: %s", ep.Name)`) - gfile.P("}") - gfile.P(`name := ep.Name[idx+1:]`) - gfile.P("m := v.MethodByName(name)") - gfile.P("if !m.IsValid() || m.IsZero() {") - gfile.P(`return `, fmtPackage.Ident("Errorf"), `("invalid handler, method %s not found", name)`) - gfile.P("}") - gfile.P("rh, ok := m.Interface().(func(", httpPackage.Ident("ResponseWriter"), ", *", httpPackage.Ident("Request"), "))") - gfile.P("if !ok {") - gfile.P(`return `, fmtPackage.Ident("Errorf"), `("invalid handler: %#+v", m.Interface())`) - gfile.P("}") - gfile.P("r.With(", chiMiddlewarePackage.Ident("WithValue"), `(routeKey{}, ep.Name)).MethodFunc(ep.Method, ep.Path, rh)`) - gfile.P("}") - gfile.P("return nil") - gfile.P("}") - } - - return nil -} diff --git a/clean.go b/clean.go new file mode 100644 index 0000000..2c1b4fe --- /dev/null +++ b/clean.go @@ -0,0 +1,50 @@ +package main + +import ( + "go/parser" + "go/token" + "os" + "path/filepath" + "strings" +) + +func isGenerated(name string) bool { + const ( + genCodeGenerated = "code generated" + genDoNotEdit = "do not edit" + genAutoFile = "autogenerated file" + ) + + markers := []string{genCodeGenerated, genDoNotEdit, genAutoFile} + + fileset := token.NewFileSet() + syntax, err := parser.ParseFile(fileset, name, nil, parser.PackageClauseOnly|parser.ParseComments) + if err != nil { + return false + } + + for _, comment := range syntax.Comments { + for _, marker := range markers { + if strings.Contains(strings.ToLower(comment.Text()), marker) { + return true + } + } + } + + return false +} + +func cleanDir(dir string) error { + return filepath.Walk(dir, func(path string, info os.FileInfo, err error) error { + if err != nil { + return err + } + if dir == "vendor" { + return filepath.SkipDir + } + if isGenerated(path) { + err = os.Remove(path) + } + return err + }) +} diff --git a/clone.go b/clone.go new file mode 100644 index 0000000..1cb03c6 --- /dev/null +++ b/clone.go @@ -0,0 +1,104 @@ +package main + +import ( + "context" + "fmt" + "go/types" + "net/url" + "os" + "path/filepath" + "strings" + + "github.com/go-git/go-git/v5" + "github.com/go-git/go-git/v5/plumbing/filemode" + "github.com/go-git/go-git/v5/plumbing/object" + "github.com/go-git/go-git/v5/storage/memory" +) + +func clone(srcRepo string, dstDir string) error { + if !strings.HasPrefix(srcRepo, "https://") { + srcRepo = "https://" + srcRepo + } + + u, err := url.Parse(srcRepo) + if err != nil { + return err + } + + var rev string + if idx := strings.Index(u.Path, "@"); idx > 0 { + rev = u.Path[idx+1:] + } + + cloneOpts := &git.CloneOptions{ + URL: srcRepo, + // Progress: os.Stdout, + } + + if len(rev) == 0 { + cloneOpts.SingleBranch = true + cloneOpts.Depth = 1 + } + + if err := cloneOpts.Validate(); err != nil { + return err + } + + repo, err := git.CloneContext(context.Background(), memory.NewStorage(), nil, cloneOpts) + if err != nil { + return err + } + + ref, err := repo.Head() + if err != nil { + return err + } + + commit, err := repo.CommitObject(ref.Hash()) + if err != nil { + return err + } + + tree, err := commit.Tree() + if err != nil { + return err + } + + if err := os.MkdirAll(dstDir, os.FileMode(0755)); err != nil { + return err + } + + if err := cleanDir(dstDir); err != nil { + return err + } + + err = tree.Files().ForEach(func(file *object.File) error { + if file == nil { + return types.Error{Msg: "file pointer is empty"} + } + + fmode, err := file.Mode.ToOSFileMode() + if err != nil { + return err + } + + switch file.Mode { + case filemode.Executable: + return writeFile(file, dstDir, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, fmode) + case filemode.Dir: + return os.MkdirAll(filepath.Join(dstDir, file.Name), fmode) + case filemode.Regular: + return writeFile(file, dstDir, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, fmode) + default: + return fmt.Errorf("unsupported filetype %v for %s", file.Mode, file.Name) + } + + return nil + }) + + if err != nil { + return err + } + + return nil +} diff --git a/copy.go b/copy.go new file mode 100644 index 0000000..59d1054 --- /dev/null +++ b/copy.go @@ -0,0 +1,46 @@ +package main + +import ( + "io" + "log" + "os" + "path/filepath" + + "github.com/go-git/go-git/v5/plumbing/object" +) + +func writeFile(file *object.File, dir string, flag int, mode os.FileMode) error { + path := filepath.Join(dir, file.Name) + + if err := os.MkdirAll(filepath.Dir(path), os.FileMode(0755)); err != nil { + return err + } + + w, err := os.OpenFile(path, flag, mode) + if err != nil { + return err + } + + defer func() { + if err := w.Close(); err != nil { + log.Printf("Err: failed to close file: %v", err) + } + }() + + r, err := file.Reader() + if err != nil { + return err + } + + defer func() { + if err := r.Close(); err != nil { + log.Printf("Err: failed to close file: %v", err) + } + }() + + if _, err = io.Copy(w, r); err != nil { + return err + } + + return nil +} diff --git a/encoder.go b/encoder.go new file mode 100644 index 0000000..cc2b02c --- /dev/null +++ b/encoder.go @@ -0,0 +1,291 @@ +package main + +import ( + "bytes" + "encoding/base64" + "fmt" + "io/ioutil" + "log" + "net/url" + "os" + "path/filepath" + "strings" + "text/template" + "time" + + "github.com/golang/protobuf/protoc-gen-go/descriptor" + plugin_go "github.com/golang/protobuf/protoc-gen-go/plugin" + "github.com/unistack-org/protoc-gen-micro/v3/assets" + pgghelpers "github.com/unistack-org/protoc-gen-micro/v3/helpers" +) + +type GenericTemplateBasedEncoder struct { + templateDir string + service *descriptor.ServiceDescriptorProto + file *descriptor.FileDescriptorProto + enum []*descriptor.EnumDescriptorProto + debug bool + destinationDir string +} + +type Ast struct { + BuildDate time.Time `json:"build-date"` + BuildHostname string `json:"build-hostname"` + BuildUser string `json:"build-user"` + GoPWD string `json:"go-pwd,omitempty"` + PWD string `json:"pwd"` + Debug bool `json:"debug"` + DestinationDir string `json:"destination-dir"` + File *descriptor.FileDescriptorProto `json:"file"` + RawFilename string `json:"raw-filename"` + Filename string `json:"filename"` + TemplateDir string `json:"template-dir"` + Service *descriptor.ServiceDescriptorProto `json:"service"` + Enum []*descriptor.EnumDescriptorProto `json:"enum"` +} + +func NewGenericServiceTemplateBasedEncoder(templateDir string, service *descriptor.ServiceDescriptorProto, file *descriptor.FileDescriptorProto, debug bool, destinationDir string) (e *GenericTemplateBasedEncoder) { + e = &GenericTemplateBasedEncoder{ + service: service, + file: file, + templateDir: templateDir, + debug: debug, + destinationDir: destinationDir, + enum: file.GetEnumType(), + } + if debug { + log.Printf("new encoder: file=%q service=%q template-dir=%q", file.GetName(), service.GetName(), templateDir) + } + pgghelpers.InitPathMap(file) + + return +} + +func NewGenericTemplateBasedEncoder(templateDir string, file *descriptor.FileDescriptorProto, debug bool, destinationDir string) (e *GenericTemplateBasedEncoder) { + e = &GenericTemplateBasedEncoder{ + service: nil, + file: file, + templateDir: templateDir, + enum: file.GetEnumType(), + debug: debug, + destinationDir: destinationDir, + } + if debug { + log.Printf("new encoder: file=%q template-dir=%q", file.GetName(), templateDir) + } + pgghelpers.InitPathMap(file) + + return +} + +func (e *GenericTemplateBasedEncoder) templates() ([]string, error) { + filenames := []string{} + + if e.templateDir == "" { + dir, err := assets.Assets.Open("/") + if err != nil { + return nil, fmt.Errorf("failed to open assets dir") + } + + fi, err := dir.Readdir(-1) + if err != nil { + return nil, fmt.Errorf("failed to get assets files") + } + + if debug { + log.Printf("components to generate: %v", components) + } + + for _, f := range fi { + name := f.Name() + skip := true + if dname, err := base64.StdEncoding.DecodeString(name); err == nil { + name = string(dname) + } + for _, component := range components { + if component == "all" || strings.Contains(name, "_"+component+".pb.go.tmpl") { + skip = false + } + } + if skip { + if debug { + log.Printf("skip template %s", name) + } + continue + } + + if f.IsDir() { + continue + } + if filepath.Ext(name) != ".tmpl" { + continue + } + if e.debug { + log.Printf("new template: %q", name) + } + + filenames = append(filenames, name) + } + + return filenames, nil + } + + err := filepath.Walk(e.templateDir, func(path string, info os.FileInfo, err error) error { + if err != nil { + return err + } + if info.IsDir() { + return nil + } + if filepath.Ext(path) != ".tmpl" { + return nil + } + rel, err := filepath.Rel(e.templateDir, path) + if err != nil { + return err + } + if e.debug { + log.Printf("new template: %q", rel) + } + + filenames = append(filenames, rel) + return nil + }) + return filenames, err +} + +func (e *GenericTemplateBasedEncoder) genAst(templateFilename string) (*Ast, error) { + // prepare the ast passed to the template engine + hostname, err := os.Hostname() + if err != nil { + return nil, err + } + pwd, err := os.Getwd() + if err != nil { + return nil, err + } + goPwd := "" + if os.Getenv("GOPATH") != "" { + goPwd, err = filepath.Rel(os.Getenv("GOPATH")+"/src", pwd) + if err != nil { + return nil, err + } + if strings.Contains(goPwd, "../") { + goPwd = "" + } + } + ast := Ast{ + BuildDate: time.Now(), + BuildHostname: hostname, + BuildUser: os.Getenv("USER"), + PWD: pwd, + GoPWD: goPwd, + File: e.file, + TemplateDir: e.templateDir, + DestinationDir: e.destinationDir, + RawFilename: templateFilename, + Filename: "", + Service: e.service, + Enum: e.enum, + } + buffer := new(bytes.Buffer) + + unescaped, err := url.QueryUnescape(templateFilename) + if err != nil { + log.Printf("failed to unescape filepath %q: %v", templateFilename, err) + } else { + templateFilename = unescaped + } + + tmpl, err := template.New("").Funcs(pgghelpers.ProtoHelpersFuncMap).Parse(templateFilename) + if err != nil { + return nil, err + } + if err := tmpl.Execute(buffer, ast); err != nil { + return nil, err + } + ast.Filename = buffer.String() + return &ast, nil +} + +func (e *GenericTemplateBasedEncoder) buildContent(templateFilename string) (string, string, error) { + var tmpl *template.Template + var err error + + if e.templateDir == "" { + fs, err := assets.Assets.Open("/" + string(base64.StdEncoding.EncodeToString([]byte(templateFilename)))) + if err != nil { + fs, err = assets.Assets.Open("/" + templateFilename) + } + if err != nil { + return "", "", err + } + buf, err := ioutil.ReadAll(fs) + if err != nil { + return "", "", err + } + if err = fs.Close(); err == nil { + tmpl, err = template.New("/" + templateFilename).Funcs(pgghelpers.ProtoHelpersFuncMap).Parse(string(buf)) + } + } else { + // initialize template engine + fullPath := filepath.Join(e.templateDir, templateFilename) + templateName := filepath.Base(fullPath) + tmpl, err = template.New(templateName).Funcs(pgghelpers.ProtoHelpersFuncMap).ParseFiles(fullPath) + } + if err != nil { + return "", "", err + } else if tmpl == nil { + return "", "", fmt.Errorf("template for %s is nil", templateFilename) + } + + ast, err := e.genAst(templateFilename) + if err != nil { + return "", "", err + } + + // generate the content + buffer := new(bytes.Buffer) + if err := tmpl.Execute(buffer, ast); err != nil { + return "", "", err + } + + return buffer.String(), ast.Filename, nil +} + +func (e *GenericTemplateBasedEncoder) Files() []*plugin_go.CodeGeneratorResponse_File { + templates, err := e.templates() + if err != nil { + log.Fatalf("cannot get templates from %q: %v", e.templateDir, err) + } + + length := len(templates) + files := make([]*plugin_go.CodeGeneratorResponse_File, 0, length) + errChan := make(chan error, length) + resultChan := make(chan *plugin_go.CodeGeneratorResponse_File, length) + for _, templateFilename := range templates { + go func(tmpl string) { + var translatedFilename, content string + content, translatedFilename, err = e.buildContent(tmpl) + if err != nil { + errChan <- err + return + } + filename := translatedFilename[:len(translatedFilename)-len(".tmpl")] + + resultChan <- &plugin_go.CodeGeneratorResponse_File{ + Content: &content, + Name: &filename, + } + }(templateFilename) + } + for i := 0; i < length; i++ { + select { + case f := <-resultChan: + files = append(files, f) + case err = <-errChan: + panic(err) + } + } + return files +} diff --git a/example/example.proto b/example/example.proto deleted file mode 100644 index 5ddc46f..0000000 --- a/example/example.proto +++ /dev/null @@ -1,44 +0,0 @@ -syntax = "proto3"; - -package example; - -option go_package = "github.com/unistack-org/protoc-gen-go-micro/v4/example;examplepb"; - -import "tag/tag.proto"; -import "api/annotations.proto"; -import "openapiv2/annotations.proto"; -import "google/protobuf/wrappers.proto"; - -service Example { - rpc Call(CallReq) returns (CallRsp) { - option (micro.openapiv3.openapiv3_operation) = { - operation_id: "Call"; - responses: { - key: "default"; - value: { - description: "Error response"; - schema: { - json_schema: { - ref: ".example.Error"; - } - } - } - } - }; - option (micro.api.http) = { post: "/v1/example/call/{name}"; body: "*"; }; - option (micro.api.micro_method) = { timeout: "5s"; }; - }; -}; - -message CallReq { - string name = 1 [(micro.tag.tags) = "xml:\",attr\"" ]; - string req = 2; -}; - -message CallRsp { - string rsp = 2; -}; - -message Error { - string msg = 1; -}; diff --git a/fiealaligment.go b/fiealaligment.go deleted file mode 100644 index 1446473..0000000 --- a/fiealaligment.go +++ /dev/null @@ -1,24 +0,0 @@ -package main - -import ( - "log" - "os" - - "golang.org/x/tools/go/analysis/passes/fieldalignment" - "golang.org/x/tools/go/analysis/singlechecker" - "google.golang.org/protobuf/compiler/protogen" -) - -func (g *Generator) fieldAlign(plugin *protogen.Plugin) error { - if !g.fieldaligment { - return nil - } - - log.Printf("%v\n", []string{"fieldalignment", "-fix", g.tagPath}) - origArgs := os.Args - os.Args = []string{"fieldalignment", "-fix", g.tagPath} - singlechecker.Main(fieldalignment.Analyzer) - os.Args = origArgs - - return nil -} diff --git a/generate.go b/generate.go new file mode 100644 index 0000000..f7fe84c --- /dev/null +++ b/generate.go @@ -0,0 +1,3 @@ +package main + +//go:generate go run -tags dev assets.go diff --git a/go.mod b/go.mod index 4f522c7..e92d5d4 100644 --- a/go.mod +++ b/go.mod @@ -1,18 +1,19 @@ -module go.unistack.org/protoc-gen-go-micro/v4 +module github.com/unistack-org/protoc-gen-micro/v3 -go 1.19 +go 1.15 require ( - github.com/fatih/structtag v1.2.0 - go.unistack.org/micro-proto/v4 v4.0.1 - golang.org/x/tools v0.11.0 - google.golang.org/protobuf v1.31.0 -) - -require ( - github.com/golang/protobuf v1.5.3 // indirect - github.com/google/gnostic v0.6.9 // indirect - golang.org/x/mod v0.12.0 // indirect - golang.org/x/sys v0.10.0 // indirect - gopkg.in/yaml.v3 v3.0.1 // indirect + github.com/Masterminds/sprig/v3 v3.2.2 + github.com/go-git/go-git/v5 v5.2.0 + github.com/golang/protobuf v1.4.3 + github.com/grpc-ecosystem/grpc-gateway/v2/v2 v2.2.0 + github.com/grpc-ecosystem/grpc-gateway/v2 v2.2.0 + github.com/huandu/xstrings v1.3.2 + github.com/mitchellh/reflectwalk v1.0.1 // indirect + github.com/shurcooL/httpfs v0.0.0-20190707220628-8d4bc4ba7749 // indirect + github.com/shurcooL/vfsgen v0.0.0-20200824052919-0d455de96546 + golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a // indirect + golang.org/x/net v0.0.0-20200904194848-62affa334b73 // indirect + google.golang.org/genproto v0.0.0-20210218151259-fe80b386bf06 + google.golang.org/protobuf v1.25.0 ) diff --git a/go.sum b/go.sum index 4ca0782..e2aa93d 100644 --- a/go.sum +++ b/go.sum @@ -1,33 +1,113 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= +cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= +cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= +cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= +cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= +cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= +cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= +cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= +cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= +cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= +cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= +cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= +cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= +cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= +cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= +cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= +cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= +cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= +cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= +cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= +cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= +cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= +cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= +cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= +cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= +cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= +cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= +cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= +cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= +cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= +dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= +github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/Masterminds/goutils v1.1.0 h1:zukEsf/1JZwCMgHiK3GZftabmxiCw4apj3a28RPBiVg= +github.com/Masterminds/goutils v1.1.0/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU= +github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI= +github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU= +github.com/Masterminds/semver/v3 v3.1.1 h1:hLg3sBzpNErnxhQtUy/mmLR2I9foDujNK030IGemrRc= +github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs= +github.com/Masterminds/sprig/v3 v3.2.0 h1:P1ekkbuU73Ui/wS0nK1HOM37hh4xdfZo485UPf8rc+Y= +github.com/Masterminds/sprig/v3 v3.2.0/go.mod h1:tWhwTbUTndesPNeF0C900vKoq283u6zp4APT9vaF3SI= +github.com/Masterminds/sprig/v3 v3.2.2 h1:17jRggJu518dr3QaafizSXOjKYp94wKfABxUmyxvxX8= +github.com/Masterminds/sprig/v3 v3.2.2/go.mod h1:UoaO7Yp8KlPnJIYWTFkMaqPUYKTfGFPhxNuwnnxkKlk= +github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7 h1:uSoVVbwJiQipAclBbw+8quDsfcvFjOpI5iCf4p/cqCs= +github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7/go.mod h1:6zEj6s6u/ghQa61ZWa/C2Aw3RkjiTBOix7dkqa1VLIs= +github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239 h1:kFOfPq6dUM1hTo4JG6LR5AXSUEsOjtdm0kw0FtQtMJA= +github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= +github.com/antihax/optional v0.0.0-20180407024304-ca021399b1a6/go.mod h1:V8iCPQYkqmusNa815XgQio277wI47sdRh1dUOLdyC6Q= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= -github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0= +github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= +github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= +github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= +github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= -github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= +github.com/emirpasic/gods v1.12.0 h1:QAUIPSaCu4G+POclxeqb3F+WPpdKqFGlw36+yOzGlrg= +github.com/emirpasic/gods v1.12.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= +github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= -github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/fatih/structtag v1.2.0 h1:/OdNE99OxoI/PqaW/SuSK9uxxT3f/tcSZgon/ssNSx4= -github.com/fatih/structtag v1.2.0/go.mod h1:mBJUNpUnHmRKrKlQQlmCrh5PuhftFbNv8Ys4/aAZl94= -github.com/flowstack/go-jsonschema v0.1.1/go.mod h1:yL7fNggx1o8rm9RlgXv7hTBWxdBM0rVwpMwimd3F3N0= +github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568 h1:BHsljHzVlRcyQhjrss6TZTdY2VfCqZPbv5k3iBFa2ZQ= +github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= +github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/gliderlabs/ssh v0.2.2 h1:6zsha5zo/TWhRhwqCD3+EarCAgZ2yN28ipRnGPnwkI0= +github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= +github.com/go-git/gcfg v1.5.0 h1:Q5ViNfGF8zFgyJWPqYwA7qGFoMTEiBmdlkcfRmpIMa4= +github.com/go-git/gcfg v1.5.0/go.mod h1:5m20vg6GwYabIxaOonVkTdrILxQMpEShl1xiMF4ua+E= +github.com/go-git/go-billy/v5 v5.0.0 h1:7NQHvd9FVid8VL4qVUMm8XifBK+2xCoZ2lSk0agRrHM= +github.com/go-git/go-billy/v5 v5.0.0/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0= +github.com/go-git/go-git-fixtures/v4 v4.0.2-0.20200613231340-f56387b50c12 h1:PbKy9zOy4aAKrJ5pibIRpVO2BXnK1Tlcg+caKI7Ox5M= +github.com/go-git/go-git-fixtures/v4 v4.0.2-0.20200613231340-f56387b50c12/go.mod h1:m+ICp2rF3jDhFgEZ/8yziagdT1C+ZpZcrJjappBCDSw= +github.com/go-git/go-git/v5 v5.2.0 h1:YPBLG/3UK1we1ohRkncLjaXWLW+HKp5QNM/jTli2JgI= +github.com/go-git/go-git/v5 v5.2.0/go.mod h1:kh02eMX+wdqqxgNMEyq8YgwlIOsDOa9homkUq1PoTMs= +github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= +github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= @@ -35,104 +115,366 @@ github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:W github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.4.3 h1:JjCZWpVbqXDqFVmTfYWEVTMIYrL/NPdPSCHPJ0T/raM= github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= -github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= -github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= -github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= -github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= -github.com/google/gnostic v0.6.9 h1:ZK/5VhkoX835RikCHpSUJV9a+S3e1zLh59YnyWeBW+0= -github.com/google/gnostic v0.6.9/go.mod h1:Nm8234We1lq6iB9OmlgNv3nH91XLLVZHCDayfA3xq+E= +github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0 h1:crn/baboCvb5fXaQ0IJ1SGTsTVrWpDsCWC8EGETZijY= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= -github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.4 h1:L8R9j+yAqZuZjsqh/z+F1NCffTKKLShY6zXTItVIZ8M= +github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= +github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= +github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= +github.com/grpc-ecosystem/grpc-gateway v1.12.1 h1:zCy2xE9ablevUOrUZc3Dl72Dt+ya2FNAvC2yLYMHzi4= +github.com/grpc-ecosystem/grpc-gateway v1.12.1/go.mod h1:8XEsbTttt/W+VvjtQhLACqCisSPWTxCZ7sBRjU6iH9c= +github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo= github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= -github.com/kr/pretty v0.2.0 h1:s5hAObm+yFO5uHYt5dYjxi2rXrsnmRpJx4OYvIWUaQs= -github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.1.0 h1:EhTvIsn53GrBLl45YVHk25cUHQHwlJfq2y8b7W5IpVY= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.1.0/go.mod h1:ly5QWKtiqC7tGfzgXYtpoZYmEWx5Z82/b18ASEL+yGc= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.2.0 h1:HlJcTiqGHvaWDG7/s85d68Kw7G7FqMz+9LlcyVauOAw= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.2.0/go.mod h1:gRq9gZWcIFvz68EgWqy2qQpRbmtn5j2qLZ4zHjqiLpg= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/huandu/xstrings v1.3.1 h1:4jgBlKK6tLKFvO8u5pmYjG91cqytmDCDvGh7ECVFfFs= +github.com/huandu/xstrings v1.3.1/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= +github.com/huandu/xstrings v1.3.2 h1:L18LIDzqlW6xN2rEkpdV8+oL/IXWJ1APd+vsdYy4Wdw= +github.com/huandu/xstrings v1.3.2/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= +github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/imdario/mergo v0.3.9 h1:UauaLniWCFHWd+Jp9oCEkTBj8VO/9DKg3PV3VCNMDIg= +github.com/imdario/mergo v0.3.9/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= +github.com/imdario/mergo v0.3.11 h1:3tnifQM4i+fbajXKBHXWEH+KvNHqojZ778UH75j3bGA= +github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= +github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A= +github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo= +github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= +github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= +github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd h1:Coekwdh0v2wtGp9Gmz1Ze3eVRAWJMLokvN3QjdzCHLY= +github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/mitchellh/copystructure v1.0.0 h1:Laisrj+bAB6b/yJwB5Bt3ITZhGJdqmxquMKeZ+mmkFQ= +github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw= +github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/reflectwalk v1.0.0 h1:9D+8oIskB4VJBN5SFlmc27fSlIBZaov1Wpk/IfikLNY= +github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/mitchellh/reflectwalk v1.0.1 h1:FVzMWA5RllMAKIdUSC8mdWo3XtwoecrH79BY70sEEpE= +github.com/mitchellh/reflectwalk v1.0.1/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= -github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= -github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0= +github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= +github.com/shopspring/decimal v1.2.0 h1:abSATXmQEYyShuxI4/vyW3tV1MrKAJzCZ/0zLUXYbsQ= +github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= +github.com/shurcooL/httpfs v0.0.0-20190707220628-8d4bc4ba7749 h1:bUGsEnyNbVPw06Bs80sCeARAlK8lhwqGyi6UT8ymuGk= +github.com/shurcooL/httpfs v0.0.0-20190707220628-8d4bc4ba7749/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg= +github.com/shurcooL/vfsgen v0.0.0-20200824052919-0d455de96546 h1:pXY9qYc/MP5zdvqWEUH6SjNiu7VhSjuVFTFiTcphaLU= +github.com/shurcooL/vfsgen v0.0.0-20200824052919-0d455de96546/go.mod h1:TrYk7fJVaAttu97ZZKrO9UbRa8izdowaMIZcxYMbVaw= +github.com/spf13/cast v1.3.1 h1:nFm6S0SMdyzrzcmThSipiEubIDy8WEXKNZ0UOgiRpng= +github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= -github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= -github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= -github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= -go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= -go.unistack.org/micro-proto/v4 v4.0.1 h1:2RKHgtCOOcAFgKsnngGK5bqM/6MWXOjVCdw03dbuoF8= -go.unistack.org/micro-proto/v4 v4.0.1/go.mod h1:ArmK7o+uFvxSY3dbJhKBBX4Pm1rhWdLEFf3LxBrMtec= +github.com/xanzy/ssh-agent v0.2.1 h1:TCbipTQL2JiiCprBWx9frJ2eJlCYT00NmctrHxVAr70= +github.com/xanzy/ssh-agent v0.2.1/go.mod h1:mLlQY/MoOhWBj+gOGMQkOeiEvkx+8pJSI+0Bx9h2kr4= +github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= +go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= +go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +golang.org/x/crypto v0.0.0-20190219172222-a4c6cb3142f2/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073 h1:xMPOj6Pz6UipU1wXLkrtqpHbR0AVFnyPEQq/wRWz9lM= +golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200414173820-0848c9571904/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a h1:vclmkQCjlDX5OydZ9wv8rBCcS0QyQY66Mpf/7BZbInM= +golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= +golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= +golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= +golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= +golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= +golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= +golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc= -golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= +golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= +golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= +golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= +golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= +golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191002035440-2ec189313ef0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b h1:0mm1VjtFUOIlE1SbDlwjYaDxZVDP2S5ou6y0gSgXHu8= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200301022130-244492dfa37a h1:GuSPYbZzB5/dcLNCwLQLsg3obCJtX9IJhpXkvY7kzk0= +golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200822124328-c89045814202 h1:VvcQYSHwXgi7W+TpUR6A9g6Up98WAHf3f/ulnJ62IyA= golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= -golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20200904194848-62affa334b73 h1:MXfv8rhZWmFeqX3GNZRsd6vOLoaCHjYEX3qkRo3YBUA= +golang.org/x/net v0.0.0-20200904194848-62affa334b73/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210201163806-010130855d6c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e h1:vcxGaoTs7kV8m5Np9uUNQin4BrLOthgV7252N8V+FwY= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208 h1:qwRHBd0NqMbJxfbotnDhm2ByMI1Shq4Y6oRJo21SGJA= +golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190221075227-b4e8571b14e0/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527 h1:uYVVQ9WP/Ds2ROhcaGPeIdVq0RIXVLwsHlnvJ+cT1So= +golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.10.0 h1:SqMFp9UcQJZa+pmYuAKjd9xq1f0j5rLcDIk0mj4qAsA= -golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200803210538-64077c9b5642 h1:B6caxRw+hozq68X2MY7jEpZh/cr4/aHLv9xU8Kkadrw= +golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.11.0 h1:EMCa6U9S2LtZXLAMoWiR/R8dAQFRqbAitmbJ2UKhoi8= -golang.org/x/tools v0.11.0/go.mod h1:anzJrxPjNtfgiYQYirP2CPGzGLxrH2u2QBhn6Bf3qY8= +golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= +golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200825202427-b303f430e36d h1:W07d4xkoAUSNOkOzdzXCdFGxT7o2rW4q8M34tB2i//k= +golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= +google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= +google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= +google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= +google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= +google.golang.org/genproto v0.0.0-20190927181202-20e1ac93f88c/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= +google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= +google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= -google.golang.org/genproto v0.0.0-20220107163113-42d7afdf6368/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= +google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210106152847-07624b53cd92 h1:jOTk2Z6KYaWoptUFqZ167cS8peoUPjFEXrsqfVkkCGc= +google.golang.org/genproto v0.0.0-20210106152847-07624b53cd92/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210207032614-bba0dbe2a9ea/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210211154401-3a9a48ddfd6c h1:SuFk+jAP52y1mif4Oh4KvO6pTPvrgWW7BYj6XMOsjVM= +google.golang.org/genproto v0.0.0-20210211154401-3a9a48ddfd6c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210211221406-4ccc9a5e4183 h1:5YmF1NDDcUX9p0CJqW+GQiLW0HHe7ZW5K6lsFk6mJeA= +google.golang.org/genproto v0.0.0-20210211221406-4ccc9a5e4183/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210218151259-fe80b386bf06 h1:Px6YyLaNKEo5eoniIBAv6Es0jbvyEmSYqOac64iS2Rs= +google.golang.org/genproto v0.0.0-20210218151259-fe80b386bf06/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= +google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.24.0/go.mod h1:XDChyiUovWa60DnaeDeZmSW86xtLtjtZbwvSiRnRtcA= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= +google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= +google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= +google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= -google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= -google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= +google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= +google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.0.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -141,19 +483,32 @@ google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzi google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= +google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c= google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= -google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= -google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= -google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME= +gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.3 h1:fvjTMHxHEw/mxHbtzPi3JCcKXQRAnQTBRo6YCJSVHKI= gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= -gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= +gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= +rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= +rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= diff --git a/gorilla.go b/gorilla.go deleted file mode 100644 index ff7b2dc..0000000 --- a/gorilla.go +++ /dev/null @@ -1,69 +0,0 @@ -package main - -import ( - "google.golang.org/protobuf/compiler/protogen" -) - -var gorillaPackageFiles map[protogen.GoPackageName]struct{} - -func (g *Generator) gorillaGenerate(component string, plugin *protogen.Plugin) error { - gorillaPackageFiles = make(map[protogen.GoPackageName]struct{}) - for _, file := range plugin.Files { - if !file.Generate { - continue - } - if len(file.Services) == 0 { - continue - } - if _, ok := gorillaPackageFiles[file.GoPackageName]; ok { - continue - } - - gorillaPackageFiles[file.GoPackageName] = struct{}{} - gname := "micro" + "_" + component + ".pb.go" - - path := file.GoImportPath - if g.standalone { - path = "." - } - gfile := plugin.NewGeneratedFile(gname, path) - - gfile.P("// Code generated by protoc-gen-go-micro. DO NOT EDIT.") - gfile.P("// protoc-gen-go-micro version: " + versionComment) - gfile.P() - gfile.P("package ", file.GoPackageName) - gfile.P() - - gfile.Import(fmtPackage) - gfile.Import(httpPackage) - gfile.Import(reflectPackage) - gfile.Import(stringsPackage) - gfile.Import(gorillaMuxPackage) - - gfile.P("func RegisterHandlers(r *", gorillaMuxPackage.Ident("Router"), ", h interface{}, eps []", microServerHttpPackage.Ident("EndpointMetadata"), ") error {") - gfile.P("v := ", reflectPackage.Ident("ValueOf"), "(h)") - gfile.P("if v.NumMethod() < 1 {") - gfile.P(`return `, fmtPackage.Ident("Errorf"), `("handler has no methods: %T", h)`) - gfile.P("}") - gfile.P("for _, ep := range eps {") - gfile.P(`idx := `, stringsPackage.Ident("Index"), `(ep.Name, ".")`) - gfile.P(`if idx < 1 || len(ep.Name) <= idx {`) - gfile.P(`return `, fmtPackage.Ident("Errorf"), `("invalid endpoint name: %s", ep.Name)`) - gfile.P("}") - gfile.P(`name := ep.Name[idx+1:]`) - gfile.P("m := v.MethodByName(name)") - gfile.P("if !m.IsValid() || m.IsZero() {") - gfile.P(`return `, fmtPackage.Ident("Errorf"), `("invalid handler, method %s not found", name)`) - gfile.P("}") - gfile.P("rh, ok := m.Interface().(func(", httpPackage.Ident("ResponseWriter"), ", *", httpPackage.Ident("Request"), "))") - gfile.P("if !ok {") - gfile.P(`return `, fmtPackage.Ident("Errorf"), `("invalid handler: %#+v", m.Interface())`) - gfile.P("}") - gfile.P(`r.HandleFunc(ep.Path, rh).Methods(ep.Method).Name(ep.Name)`) - gfile.P("}") - gfile.P("return nil") - gfile.P("}") - } - - return nil -} diff --git a/helpers/helpers.go b/helpers/helpers.go new file mode 100644 index 0000000..f42a106 --- /dev/null +++ b/helpers/helpers.go @@ -0,0 +1,1564 @@ +package pgghelpers + +import ( + "encoding/json" + "fmt" + "reflect" + "regexp" + "strings" + "sync" + "text/template" + + "github.com/Masterminds/sprig/v3" + "github.com/golang/protobuf/proto" + "github.com/golang/protobuf/protoc-gen-go/descriptor" + ggdescriptor "github.com/grpc-ecosystem/grpc-gateway/protoc-gen-grpc-gateway/descriptor" + openapi_options "github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv2/options" + "github.com/huandu/xstrings" + options "google.golang.org/genproto/googleapis/api/annotations" + // "google.golang.org/protobuf/proto" +) + +var jsReservedRe = regexp.MustCompile(`(^|[^A-Za-z])(do|if|in|for|let|new|try|var|case|else|enum|eval|false|null|this|true|void|with|break|catch|class|const|super|throw|while|yield|delete|export|import|public|return|static|switch|typeof|default|extends|finally|package|private|continue|debugger|function|arguments|interface|protected|implements|instanceof)($|[^A-Za-z])`) + +var ( + registry *ggdescriptor.Registry // some helpers need access to registry +) + +type HttpOption struct { + Path string + Method string + Body string + Additional []*HttpOption +} + +var ProtoHelpersFuncMap = template.FuncMap{ + "string": func(i interface { + String() string + }) string { + return i.String() + }, + "json": func(v interface{}) string { + a, err := json.Marshal(v) + if err != nil { + return err.Error() + } + return string(a) + }, + "prettyjson": func(v interface{}) string { + a, err := json.MarshalIndent(v, "", " ") + if err != nil { + return err.Error() + } + return string(a) + }, + "splitArray": func(sep string, s string) []string { + var r []string + parts := strings.Split(s, sep) + for _, part := range parts { + if part != "" { + r = append(r, part) + } + } + return r + }, + "first": func(a []string) string { + return a[0] + }, + "last": func(a []string) string { + return a[len(a)-1] + }, + "concat": func(a string, b ...string) string { + return strings.Join(append([]string{a}, b...), "") + }, + "join": func(sep string, a ...string) string { + return strings.Join(a, sep) + }, + "joinQuotes": func(a []string) string { + return fmt.Sprintf(`"%s"`, strings.Join(a, `", "`)) + }, + "upperFirst": func(s string) string { + return strings.ToUpper(s[:1]) + s[1:] + }, + "lowerFirst": func(s string) string { + return strings.ToLower(s[:1]) + s[1:] + }, + "camelCase": func(s string) string { + if len(s) > 1 { + return xstrings.ToCamelCase(s) + } + + return strings.ToUpper(s[:1]) + }, + "lowerCamelCase": func(s string) string { + if len(s) > 1 { + s = xstrings.ToCamelCase(s) + } + + return strings.ToLower(s[:1]) + s[1:] + }, + "upperCase": func(s string) string { + return strings.ToUpper(s) + }, + "kebabCase": func(s string) string { + return strings.Replace(xstrings.ToSnakeCase(s), "_", "-", -1) + }, + "contains": func(sub, s string) bool { + return strings.Contains(s, sub) + }, + "trimstr": func(cutset, s string) string { + return strings.Trim(s, cutset) + }, + "index": func(array interface{}, i int) interface{} { + slice := reflect.ValueOf(array) + if slice.Kind() != reflect.Slice { + panic("Error in index(): given a non-slice type") + } + if i < 0 || i >= slice.Len() { + panic("Error in index(): index out of bounds") + } + return slice.Index(i).Interface() + }, + "add": func(a int, b int) int { + return a + b + }, + "subtract": func(a int, b int) int { + return a - b + }, + "multiply": func(a int, b int) int { + return a * b + }, + "divide": func(a int, b int) int { + if b == 0 { + panic("psssst ... little help here ... you cannot divide by 0") + } + return a / b + }, + "lenght": func(a []interface{}) int { + return len(a) + }, + "snakeCase": xstrings.ToSnakeCase, + "getProtoFile": getProtoFile, + "getMessageType": getMessageType, + "getEnumValue": getEnumValue, + "isFieldMessage": isFieldMessage, + "isFieldMessageTimeStamp": isFieldMessageTimeStamp, + "isFieldRepeated": isFieldRepeated, + "haskellType": haskellType, + "goType": goType, + "goZeroValue": goZeroValue, + "goTypeWithPackage": goTypeWithPackage, + "goTypeWithGoPackage": goTypeWithGoPackage, + "jsType": jsType, + "jsSuffixReserved": jsSuffixReservedKeyword, + "namespacedFlowType": namespacedFlowType, + "openapiOption": openapiOption, + "httpOption": httpOption, + "httpVerb": httpVerb, + "httpPath": httpPath, + "httpPathsAdditionalBindings": httpPathsAdditionalBindings, + "httpBody": httpBody, + "shortType": shortType, + "urlHasVarsFromMessage": urlHasVarsFromMessage, + "lowerGoNormalize": lowerGoNormalize, + "goNormalize": goNormalize, + "leadingComment": leadingComment, + "trailingComment": trailingComment, + "leadingDetachedComments": leadingDetachedComments, + "stringFileOptionsExtension": stringFileOptionsExtension, + "stringMessageExtension": stringMessageExtension, + "stringFieldExtension": stringFieldExtension, + "int64FieldExtension": int64FieldExtension, + "int64MessageExtension": int64MessageExtension, + "stringMethodOptionsExtension": stringMethodOptionsExtension, + "boolMethodOptionsExtension": boolMethodOptionsExtension, + "boolMessageExtension": boolMessageExtension, + "boolFieldExtension": boolFieldExtension, + "isFieldMap": isFieldMap, + "fieldMapKeyType": fieldMapKeyType, + "fieldMapValueType": fieldMapValueType, + "replaceDict": replaceDict, + "setStore": setStore, + "getStore": getStore, + "goPkg": goPkg, + "goPkgLastElement": goPkgLastElement, + "cppType": cppType, + "cppTypeWithPackage": cppTypeWithPackage, + "rustType": rustType, + "rustTypeWithPackage": rustTypeWithPackage, +} + +var pathMap map[interface{}]*descriptor.SourceCodeInfo_Location + +var store = newStore() + +// Utility to store some vars across multiple scope +type globalStore struct { + store map[string]interface{} + mu sync.Mutex +} + +func newStore() *globalStore { + return &globalStore{ + store: make(map[string]interface{}), + } +} + +func (s *globalStore) getData(key string) interface{} { + s.mu.Lock() + defer s.mu.Unlock() + + if v, ok := s.store[key]; ok { + return v + } + + return false +} + +func (s *globalStore) setData(key string, o interface{}) { + s.mu.Lock() + s.store[key] = o + s.mu.Unlock() +} + +func setStore(key string, o interface{}) string { + store.setData(key, o) + return "" +} + +func getStore(key string) interface{} { + return store.getData(key) +} + +func SetRegistry(reg *ggdescriptor.Registry) { + registry = reg +} + +func InitPathMap(file *descriptor.FileDescriptorProto) { + pathMap = make(map[interface{}]*descriptor.SourceCodeInfo_Location) + addToPathMap(file.GetSourceCodeInfo(), file, []int32{}) +} + +func InitPathMaps(files []*descriptor.FileDescriptorProto) { + pathMap = make(map[interface{}]*descriptor.SourceCodeInfo_Location) + for _, file := range files { + addToPathMap(file.GetSourceCodeInfo(), file, []int32{}) + } +} + +// addToPathMap traverses through the AST adding SourceCodeInfo_Location entries to the pathMap. +// Since the AST is a tree, the recursion finishes once it has gone through all the nodes. +func addToPathMap(info *descriptor.SourceCodeInfo, i interface{}, path []int32) { + loc := findLoc(info, path) + if loc != nil { + pathMap[i] = loc + } + switch d := i.(type) { + case *descriptor.FileDescriptorProto: + for index, descriptor := range d.MessageType { + addToPathMap(info, descriptor, newPath(path, 4, index)) + } + for index, descriptor := range d.EnumType { + addToPathMap(info, descriptor, newPath(path, 5, index)) + } + for index, descriptor := range d.Service { + addToPathMap(info, descriptor, newPath(path, 6, index)) + } + case *descriptor.DescriptorProto: + for index, descriptor := range d.Field { + addToPathMap(info, descriptor, newPath(path, 2, index)) + } + for index, descriptor := range d.NestedType { + addToPathMap(info, descriptor, newPath(path, 3, index)) + } + for index, descriptor := range d.EnumType { + addToPathMap(info, descriptor, newPath(path, 4, index)) + } + case *descriptor.EnumDescriptorProto: + for index, descriptor := range d.Value { + addToPathMap(info, descriptor, newPath(path, 2, index)) + } + case *descriptor.ServiceDescriptorProto: + for index, descriptor := range d.Method { + addToPathMap(info, descriptor, newPath(path, 2, index)) + } + } +} + +func newPath(base []int32, field int32, index int) []int32 { + p := append([]int32{}, base...) + p = append(p, field, int32(index)) + return p +} + +func findLoc(info *descriptor.SourceCodeInfo, path []int32) *descriptor.SourceCodeInfo_Location { + for _, loc := range info.GetLocation() { + if samePath(loc.Path, path) { + return loc + } + } + return nil +} + +func samePath(a, b []int32) bool { + if len(a) != len(b) { + return false + } + for i, p := range a { + if p != b[i] { + return false + } + } + return true +} + +/*func findSourceInfoLocation(i interface{}) *descriptor.SourceCodeInfo_Location { + if pathMap == nil { + return nil + } + return pathMap[i] +}*/ + +func leadingComment(i interface{}) string { + loc := pathMap[i] + return loc.GetLeadingComments() +} +func trailingComment(i interface{}) string { + loc := pathMap[i] + return loc.GetTrailingComments() +} +func leadingDetachedComments(i interface{}) []string { + loc := pathMap[i] + return loc.GetLeadingDetachedComments() +} + +// stringMethodOptionsExtension extracts method options of a string type. +// To define your own extensions see: +// https://developers.google.com/protocol-buffers/docs/proto#customoptions +// Typically the fieldID of private extensions should be in the range: +// 50000-99999 +func stringMethodOptionsExtension(fieldID int32, f *descriptor.MethodDescriptorProto) string { + if f == nil { + return "" + } + if f.Options == nil { + return "" + } + var extendedType *descriptor.MethodOptions + var extensionType *string + + eds := proto.RegisteredExtensions(f.Options) + if eds[fieldID] == nil { + ed := &proto.ExtensionDesc{ + ExtendedType: extendedType, + ExtensionType: extensionType, + Field: fieldID, + Tag: fmt.Sprintf("bytes,%d", fieldID), + } + proto.RegisterExtension(ed) + eds = proto.RegisteredExtensions(f.Options) + } + + ext, err := proto.GetExtension(f.Options, eds[fieldID]) + if err != nil { + return "" + } + + str, ok := ext.(*string) + if !ok { + return "" + } + + return *str +} + +// stringFileOptionsExtension extracts file options of a string type. +// To define your own extensions see: +// https://developers.google.com/protocol-buffers/docs/proto#customoptions +// Typically the fieldID of private extensions should be in the range: +// 50000-99999 +func stringFileOptionsExtension(fieldID int32, f *descriptor.FileDescriptorProto) string { + if f == nil { + return "" + } + if f.Options == nil { + return "" + } + var extendedType *descriptor.FileOptions + var extensionType *string + + eds := proto.RegisteredExtensions(f.Options) + if eds[fieldID] == nil { + ed := &proto.ExtensionDesc{ + ExtendedType: extendedType, + ExtensionType: extensionType, + Field: fieldID, + Tag: fmt.Sprintf("bytes,%d", fieldID), + } + proto.RegisterExtension(ed) + eds = proto.RegisteredExtensions(f.Options) + } + + ext, err := proto.GetExtension(f.Options, eds[fieldID]) + if err != nil { + return "" + } + + str, ok := ext.(*string) + if !ok { + return "" + } + + return *str +} + +func stringFieldExtension(fieldID int32, f *descriptor.FieldDescriptorProto) string { + if f == nil { + return "" + } + if f.Options == nil { + return "" + } + var extendedType *descriptor.FieldOptions + var extensionType *string + + eds := proto.RegisteredExtensions(f.Options) + if eds[fieldID] == nil { + ed := &proto.ExtensionDesc{ + ExtendedType: extendedType, + ExtensionType: extensionType, + Field: fieldID, + Tag: fmt.Sprintf("bytes,%d", fieldID), + } + proto.RegisterExtension(ed) + eds = proto.RegisteredExtensions(f.Options) + } + + ext, err := proto.GetExtension(f.Options, eds[fieldID]) + if err != nil { + return "" + } + + str, ok := ext.(*string) + if !ok { + return "" + } + + return *str +} + +func int64FieldExtension(fieldID int32, f *descriptor.FieldDescriptorProto) int64 { + if f == nil { + return 0 + } + if f.Options == nil { + return 0 + } + var extendedType *descriptor.FieldOptions + var extensionType *int64 + + eds := proto.RegisteredExtensions(f.Options) + if eds[fieldID] == nil { + ed := &proto.ExtensionDesc{ + ExtendedType: extendedType, + ExtensionType: extensionType, + Field: fieldID, + Tag: fmt.Sprintf("varint,%d", fieldID), + } + proto.RegisterExtension(ed) + eds = proto.RegisteredExtensions(f.Options) + } + + ext, err := proto.GetExtension(f.Options, eds[fieldID]) + if err != nil { + return 0 + } + + i, ok := ext.(*int64) + if !ok { + return 0 + } + + return *i +} + +func int64MessageExtension(fieldID int32, f *descriptor.DescriptorProto) int64 { + if f == nil { + return 0 + } + if f.Options == nil { + return 0 + } + var extendedType *descriptor.MessageOptions + var extensionType *int64 + + eds := proto.RegisteredExtensions(f.Options) + if eds[fieldID] == nil { + ed := &proto.ExtensionDesc{ + ExtendedType: extendedType, + ExtensionType: extensionType, + Field: fieldID, + Tag: fmt.Sprintf("varint,%d", fieldID), + } + proto.RegisterExtension(ed) + eds = proto.RegisteredExtensions(f.Options) + } + + ext, err := proto.GetExtension(f.Options, eds[fieldID]) + if err != nil { + return 0 + } + + i, ok := ext.(*int64) + if !ok { + return 0 + } + + return *i +} + +func stringMessageExtension(fieldID int32, f *descriptor.DescriptorProto) string { + if f == nil { + return "" + } + if f.Options == nil { + return "" + } + var extendedType *descriptor.MessageOptions + var extensionType *string + + eds := proto.RegisteredExtensions(f.Options) + if eds[fieldID] == nil { + ed := &proto.ExtensionDesc{ + ExtendedType: extendedType, + ExtensionType: extensionType, + Field: fieldID, + Tag: fmt.Sprintf("bytes,%d", fieldID), + } + proto.RegisterExtension(ed) + eds = proto.RegisteredExtensions(f.Options) + } + + ext, err := proto.GetExtension(f.Options, eds[fieldID]) + if err != nil { + return "" + } + + str, ok := ext.(*string) + if !ok { + return "" + } + + return *str +} + +func boolMethodOptionsExtension(fieldID int32, f *descriptor.MethodDescriptorProto) bool { + if f == nil { + return false + } + if f.Options == nil { + return false + } + var extendedType *descriptor.MethodOptions + var extensionType *bool + + eds := proto.RegisteredExtensions(f.Options) + if eds[fieldID] == nil { + ed := &proto.ExtensionDesc{ + ExtendedType: extendedType, + ExtensionType: extensionType, + Field: fieldID, + Tag: fmt.Sprintf("varint,%d", fieldID), + } + proto.RegisterExtension(ed) + eds = proto.RegisteredExtensions(f.Options) + } + + ext, err := proto.GetExtension(f.Options, eds[fieldID]) + if err != nil { + return false + } + + b, ok := ext.(*bool) + if !ok { + return false + } + + return *b +} + +func boolFieldExtension(fieldID int32, f *descriptor.FieldDescriptorProto) bool { + if f == nil { + return false + } + if f.Options == nil { + return false + } + var extendedType *descriptor.FieldOptions + var extensionType *bool + + eds := proto.RegisteredExtensions(f.Options) + if eds[fieldID] == nil { + ed := &proto.ExtensionDesc{ + ExtendedType: extendedType, + ExtensionType: extensionType, + Field: fieldID, + Tag: fmt.Sprintf("varint,%d", fieldID), + } + proto.RegisterExtension(ed) + eds = proto.RegisteredExtensions(f.Options) + } + + ext, err := proto.GetExtension(f.Options, eds[fieldID]) + if err != nil { + return false + } + + b, ok := ext.(*bool) + if !ok { + return false + } + + return *b +} + +func boolMessageExtension(fieldID int32, f *descriptor.DescriptorProto) bool { + if f == nil { + return false + } + if f.Options == nil { + return false + } + var extendedType *descriptor.MessageOptions + var extensionType *bool + + eds := proto.RegisteredExtensions(f.Options) + if eds[fieldID] == nil { + ed := &proto.ExtensionDesc{ + ExtendedType: extendedType, + ExtensionType: extensionType, + Field: fieldID, + Tag: fmt.Sprintf("varint,%d", fieldID), + } + proto.RegisterExtension(ed) + eds = proto.RegisteredExtensions(f.Options) + } + + ext, err := proto.GetExtension(f.Options, eds[fieldID]) + if err != nil { + return false + } + + b, ok := ext.(*bool) + if !ok { + return false + } + + return *b +} + +func init() { + for k, v := range sprig.TxtFuncMap() { + ProtoHelpersFuncMap[k] = v + } +} + +func getProtoFile(name string) *ggdescriptor.File { + if registry == nil { + return nil + } + file, err := registry.LookupFile(name) + if err != nil { + panic(err) + } + return file +} + +func getMessageType(f *descriptor.FileDescriptorProto, name string) *ggdescriptor.Message { + if registry != nil { + msg, err := registry.LookupMsg(".", name) + if err != nil { + panic(err) + } + return msg + } + + // name is in the form .packageName.MessageTypeName.InnerMessageTypeName... + // e.g. .article.ProductTag + splits := strings.Split(name, ".") + target := splits[len(splits)-1] + for _, m := range f.MessageType { + if target == *m.Name { + return &ggdescriptor.Message{ + DescriptorProto: m, + } + } + } + return nil +} + +func getEnumValue(f []*descriptor.EnumDescriptorProto, name string) []*descriptor.EnumValueDescriptorProto { + for _, item := range f { + if strings.EqualFold(*item.Name, name) { + return item.GetValue() + } + } + + return nil +} + +func isFieldMessageTimeStamp(f *descriptor.FieldDescriptorProto) bool { + if f.Type != nil && *f.Type == descriptor.FieldDescriptorProto_TYPE_MESSAGE { + if strings.Compare(*f.TypeName, ".google.protobuf.Timestamp") == 0 { + return true + } + } + return false +} + +func isFieldMessage(f *descriptor.FieldDescriptorProto) bool { + if f.Type != nil && *f.Type == descriptor.FieldDescriptorProto_TYPE_MESSAGE { + return true + } + + return false +} + +func isFieldRepeated(f *descriptor.FieldDescriptorProto) bool { + if f == nil { + return false + } + if f.Type != nil && f.Label != nil && *f.Label == descriptor.FieldDescriptorProto_LABEL_REPEATED { + return true + } + + return false +} + +func isFieldMap(f *descriptor.FieldDescriptorProto, m *descriptor.DescriptorProto) bool { + if f.TypeName == nil { + return false + } + + shortName := shortType(*f.TypeName) + var nt *descriptor.DescriptorProto + for _, t := range m.NestedType { + if *t.Name == shortName { + nt = t + break + } + } + + if nt == nil { + return false + } + + for _, f := range nt.Field { + switch *f.Name { + case "key": + if *f.Number != 1 { + return false + } + case "value": + if *f.Number != 2 { + return false + } + default: + return false + } + } + + return true +} + +func fieldMapKeyType(f *descriptor.FieldDescriptorProto, m *descriptor.DescriptorProto) *descriptor.FieldDescriptorProto { + if f.TypeName == nil { + return nil + } + + shortName := shortType(*f.TypeName) + var nt *descriptor.DescriptorProto + for _, t := range m.NestedType { + if *t.Name == shortName { + nt = t + break + } + } + + if nt == nil { + return nil + } + + for _, f := range nt.Field { + if *f.Name == "key" { + return f + } + } + + return nil + +} + +func fieldMapValueType(f *descriptor.FieldDescriptorProto, m *descriptor.DescriptorProto) *descriptor.FieldDescriptorProto { + if f.TypeName == nil { + return nil + } + + shortName := shortType(*f.TypeName) + var nt *descriptor.DescriptorProto + for _, t := range m.NestedType { + if *t.Name == shortName { + nt = t + break + } + } + + if nt == nil { + return nil + } + + for _, f := range nt.Field { + if *f.Name == "value" { + return f + } + } + + return nil + +} + +// goTypeWithGoPackage types the field MESSAGE and ENUM with the go_package name. +// This method is an evolution of goTypeWithPackage. It handles message embedded. +// +// example: +// ```proto +// message GetArticleResponse { +// Article article = 1; +// message Storage { +// string code = 1; +// } +// repeated Storage storages = 2; +// } +// ``` +// Then the type of `storages` is `GetArticleResponse_Storage` for the go language. +// +func goTypeWithGoPackage(p *descriptor.FileDescriptorProto, f *descriptor.FieldDescriptorProto) string { + pkg := "" + if *f.Type == descriptor.FieldDescriptorProto_TYPE_MESSAGE || *f.Type == descriptor.FieldDescriptorProto_TYPE_ENUM { + if isTimestampPackage(*f.TypeName) { + pkg = "timestamp" + } else { + pkg = *p.GetOptions().GoPackage + if strings.Contains(*p.GetOptions().GoPackage, ";") { + pkg = strings.Split(*p.GetOptions().GoPackage, ";")[1] + } + } + } + return goTypeWithEmbedded(pkg, f, p) +} + +// Warning does not handle message embedded like goTypeWithGoPackage does. +func goTypeWithPackage(f *descriptor.FieldDescriptorProto) string { + pkg := "" + if *f.Type == descriptor.FieldDescriptorProto_TYPE_MESSAGE || *f.Type == descriptor.FieldDescriptorProto_TYPE_ENUM { + if isTimestampPackage(*f.TypeName) { + pkg = "timestamp" + } else { + pkg = getPackageTypeName(*f.TypeName) + } + } + return goType(pkg, f) +} + +func haskellType(pkg string, f *descriptor.FieldDescriptorProto) string { + switch *f.Type { + case descriptor.FieldDescriptorProto_TYPE_DOUBLE: + if *f.Label == descriptor.FieldDescriptorProto_LABEL_REPEATED { + return "[Float]" + } + return "Float" + case descriptor.FieldDescriptorProto_TYPE_FLOAT: + if *f.Label == descriptor.FieldDescriptorProto_LABEL_REPEATED { + return "[Float]" + } + return "Float" + case descriptor.FieldDescriptorProto_TYPE_INT64: + if *f.Label == descriptor.FieldDescriptorProto_LABEL_REPEATED { + return "[Int64]" + } + return "Int64" + case descriptor.FieldDescriptorProto_TYPE_UINT64: + if *f.Label == descriptor.FieldDescriptorProto_LABEL_REPEATED { + return "[Word]" + } + return "Word" + case descriptor.FieldDescriptorProto_TYPE_INT32: + if *f.Label == descriptor.FieldDescriptorProto_LABEL_REPEATED { + return "[Int]" + } + return "Int" + case descriptor.FieldDescriptorProto_TYPE_UINT32: + if *f.Label == descriptor.FieldDescriptorProto_LABEL_REPEATED { + return "[Word]" + } + return "Word" + case descriptor.FieldDescriptorProto_TYPE_BOOL: + if *f.Label == descriptor.FieldDescriptorProto_LABEL_REPEATED { + return "[Bool]" + } + return "Bool" + case descriptor.FieldDescriptorProto_TYPE_STRING: + if *f.Label == descriptor.FieldDescriptorProto_LABEL_REPEATED { + return "[Text]" + } + return "Text" + case descriptor.FieldDescriptorProto_TYPE_MESSAGE: + if pkg != "" { + pkg = pkg + "." + } + if *f.Label == descriptor.FieldDescriptorProto_LABEL_REPEATED { + return fmt.Sprintf("[%s%s]", pkg, shortType(*f.TypeName)) + } + return fmt.Sprintf("%s%s", pkg, shortType(*f.TypeName)) + case descriptor.FieldDescriptorProto_TYPE_BYTES: + if *f.Label == descriptor.FieldDescriptorProto_LABEL_REPEATED { + return "[Word8]" + } + return "Word8" + case descriptor.FieldDescriptorProto_TYPE_ENUM: + return fmt.Sprintf("%s%s", pkg, shortType(*f.TypeName)) + default: + return "Generic" + } +} + +// Warning does not handle message embedded like goTypeWithGoPackage does. +func rustTypeWithPackage(f *descriptor.FieldDescriptorProto) string { + pkg := "" + if *f.Type == descriptor.FieldDescriptorProto_TYPE_MESSAGE || *f.Type == descriptor.FieldDescriptorProto_TYPE_ENUM { + if isTimestampPackage(*f.TypeName) { + pkg = "timestamp" + } else { + pkg = getPackageTypeName(*f.TypeName) + } + } + return rustType(pkg, f) +} + +func rustType(pkg string, f *descriptor.FieldDescriptorProto) string { + isRepeat := *f.Label == descriptor.FieldDescriptorProto_LABEL_REPEATED + typeName := "???" + switch *f.Type { + case descriptor.FieldDescriptorProto_TYPE_DOUBLE: + typeName = "f64" + case descriptor.FieldDescriptorProto_TYPE_FLOAT: + typeName = "f32" + case descriptor.FieldDescriptorProto_TYPE_INT64: + typeName = "i64" + case descriptor.FieldDescriptorProto_TYPE_UINT64: + typeName = "u64" + case descriptor.FieldDescriptorProto_TYPE_INT32: + typeName = "i32" + case descriptor.FieldDescriptorProto_TYPE_UINT32: + typeName = "u32" + case descriptor.FieldDescriptorProto_TYPE_BOOL: + typeName = "bool" + case descriptor.FieldDescriptorProto_TYPE_STRING: + typeName = "String" + case descriptor.FieldDescriptorProto_TYPE_MESSAGE: + if pkg != "" { + pkg = pkg + "." + } + typeName = fmt.Sprintf("%s%s", pkg, shortType(*f.TypeName)) + case descriptor.FieldDescriptorProto_TYPE_BYTES: + typeName = "Vec" + case descriptor.FieldDescriptorProto_TYPE_ENUM: + typeName = fmt.Sprintf("%s%s", pkg, shortType(*f.TypeName)) + default: + break + } + if isRepeat { + return "Vec<" + typeName + ">" + } + return typeName +} + +// Warning does not handle message embedded like goTypeWithGoPackage does. +func cppTypeWithPackage(f *descriptor.FieldDescriptorProto) string { + pkg := "" + if *f.Type == descriptor.FieldDescriptorProto_TYPE_MESSAGE || *f.Type == descriptor.FieldDescriptorProto_TYPE_ENUM { + if isTimestampPackage(*f.TypeName) { + pkg = "timestamp" + } else { + pkg = getPackageTypeName(*f.TypeName) + } + } + return cppType(pkg, f) +} + +func cppType(pkg string, f *descriptor.FieldDescriptorProto) string { + isRepeat := *f.Label == descriptor.FieldDescriptorProto_LABEL_REPEATED + typeName := "???" + switch *f.Type { + case descriptor.FieldDescriptorProto_TYPE_DOUBLE: + typeName = "double" + case descriptor.FieldDescriptorProto_TYPE_FLOAT: + typeName = "float" + case descriptor.FieldDescriptorProto_TYPE_INT64: + typeName = "int64_t" + case descriptor.FieldDescriptorProto_TYPE_UINT64: + typeName = "uint64_t" + case descriptor.FieldDescriptorProto_TYPE_INT32: + typeName = "int32_t" + case descriptor.FieldDescriptorProto_TYPE_UINT32: + typeName = "uint32_t" + case descriptor.FieldDescriptorProto_TYPE_BOOL: + typeName = "bool" + case descriptor.FieldDescriptorProto_TYPE_STRING: + typeName = "std::string" + case descriptor.FieldDescriptorProto_TYPE_MESSAGE: + if pkg != "" { + pkg = pkg + "." + } + typeName = fmt.Sprintf("%s%s", pkg, shortType(*f.TypeName)) + case descriptor.FieldDescriptorProto_TYPE_BYTES: + typeName = "std::vector" + case descriptor.FieldDescriptorProto_TYPE_ENUM: + typeName = fmt.Sprintf("%s%s", pkg, shortType(*f.TypeName)) + default: + break + } + if isRepeat { + return "std::vector<" + typeName + ">" + } + return typeName +} + +func goTypeWithEmbedded(pkg string, f *descriptor.FieldDescriptorProto, p *descriptor.FileDescriptorProto) string { + if pkg != "" { + pkg = pkg + "." + } + switch *f.Type { + case descriptor.FieldDescriptorProto_TYPE_DOUBLE: + if *f.Label == descriptor.FieldDescriptorProto_LABEL_REPEATED { + return "[]float64" + } + return "float64" + case descriptor.FieldDescriptorProto_TYPE_FLOAT: + if *f.Label == descriptor.FieldDescriptorProto_LABEL_REPEATED { + return "[]float32" + } + return "float32" + case descriptor.FieldDescriptorProto_TYPE_INT64: + if *f.Label == descriptor.FieldDescriptorProto_LABEL_REPEATED { + return "[]int64" + } + return "int64" + case descriptor.FieldDescriptorProto_TYPE_UINT64: + if *f.Label == descriptor.FieldDescriptorProto_LABEL_REPEATED { + return "[]uint64" + } + return "uint64" + case descriptor.FieldDescriptorProto_TYPE_INT32: + if *f.Label == descriptor.FieldDescriptorProto_LABEL_REPEATED { + return "[]int32" + } + return "int32" + case descriptor.FieldDescriptorProto_TYPE_UINT32: + if *f.Label == descriptor.FieldDescriptorProto_LABEL_REPEATED { + return "[]uint32" + } + return "uint32" + case descriptor.FieldDescriptorProto_TYPE_BOOL: + if *f.Label == descriptor.FieldDescriptorProto_LABEL_REPEATED { + return "[]bool" + } + return "bool" + case descriptor.FieldDescriptorProto_TYPE_STRING: + if *f.Label == descriptor.FieldDescriptorProto_LABEL_REPEATED { + return "[]string" + } + return "string" + case descriptor.FieldDescriptorProto_TYPE_MESSAGE: + name := *f.TypeName + if *f.Label == descriptor.FieldDescriptorProto_LABEL_REPEATED { + fieldPackage := strings.Split(*f.TypeName, ".") + filePackage := strings.Split(*p.Package, ".") + // check if we are working with a message embedded. + if len(fieldPackage) > 1 && len(fieldPackage)+1 > len(filePackage)+1 { + name = strings.Join(fieldPackage[len(filePackage)+1:], "_") + } + + return fmt.Sprintf("[]*%s%s", pkg, shortType(name)) + } + return fmt.Sprintf("*%s%s", pkg, shortType(name)) + case descriptor.FieldDescriptorProto_TYPE_BYTES: + if *f.Label == descriptor.FieldDescriptorProto_LABEL_REPEATED { + return "[]byte" + } + return "byte" + case descriptor.FieldDescriptorProto_TYPE_ENUM: + name := *f.TypeName + fieldPackage := strings.Split(*f.TypeName, ".") + filePackage := strings.Split(*p.Package, ".") + // check if we are working with a message embedded. + if len(fieldPackage) > 1 && len(fieldPackage)+1 > len(filePackage)+1 { + name = strings.Join(fieldPackage[len(filePackage)+1:], "_") + } + return fmt.Sprintf("*%s%s", pkg, shortType(name)) + default: + return "interface{}" + } +} + +//Deprecated. Instead use goTypeWithEmbedded +func goType(pkg string, f *descriptor.FieldDescriptorProto) string { + if pkg != "" { + pkg = pkg + "." + } + switch *f.Type { + case descriptor.FieldDescriptorProto_TYPE_DOUBLE: + if *f.Label == descriptor.FieldDescriptorProto_LABEL_REPEATED { + return "[]float64" + } + return "float64" + case descriptor.FieldDescriptorProto_TYPE_FLOAT: + if *f.Label == descriptor.FieldDescriptorProto_LABEL_REPEATED { + return "[]float32" + } + return "float32" + case descriptor.FieldDescriptorProto_TYPE_INT64: + if *f.Label == descriptor.FieldDescriptorProto_LABEL_REPEATED { + return "[]int64" + } + return "int64" + case descriptor.FieldDescriptorProto_TYPE_UINT64: + if *f.Label == descriptor.FieldDescriptorProto_LABEL_REPEATED { + return "[]uint64" + } + return "uint64" + case descriptor.FieldDescriptorProto_TYPE_INT32: + if *f.Label == descriptor.FieldDescriptorProto_LABEL_REPEATED { + return "[]int32" + } + return "int32" + case descriptor.FieldDescriptorProto_TYPE_UINT32: + if *f.Label == descriptor.FieldDescriptorProto_LABEL_REPEATED { + return "[]uint32" + } + return "uint32" + case descriptor.FieldDescriptorProto_TYPE_BOOL: + if *f.Label == descriptor.FieldDescriptorProto_LABEL_REPEATED { + return "[]bool" + } + return "bool" + case descriptor.FieldDescriptorProto_TYPE_STRING: + if *f.Label == descriptor.FieldDescriptorProto_LABEL_REPEATED { + return "[]string" + } + return "string" + case descriptor.FieldDescriptorProto_TYPE_MESSAGE: + if *f.Label == descriptor.FieldDescriptorProto_LABEL_REPEATED { + return fmt.Sprintf("[]*%s%s", pkg, shortType(*f.TypeName)) + } + return fmt.Sprintf("*%s%s", pkg, shortType(*f.TypeName)) + case descriptor.FieldDescriptorProto_TYPE_BYTES: + if *f.Label == descriptor.FieldDescriptorProto_LABEL_REPEATED { + return "[]byte" + } + return "byte" + case descriptor.FieldDescriptorProto_TYPE_ENUM: + return fmt.Sprintf("*%s%s", pkg, shortType(*f.TypeName)) + default: + return "interface{}" + } +} + +func goZeroValue(f *descriptor.FieldDescriptorProto) string { + const nilString = "nil" + if *f.Label == descriptor.FieldDescriptorProto_LABEL_REPEATED { + return nilString + } + switch *f.Type { + case descriptor.FieldDescriptorProto_TYPE_DOUBLE: + return "0.0" + case descriptor.FieldDescriptorProto_TYPE_FLOAT: + return "0.0" + case descriptor.FieldDescriptorProto_TYPE_INT64: + return "0" + case descriptor.FieldDescriptorProto_TYPE_UINT64: + return "0" + case descriptor.FieldDescriptorProto_TYPE_INT32: + return "0" + case descriptor.FieldDescriptorProto_TYPE_UINT32: + return "0" + case descriptor.FieldDescriptorProto_TYPE_BOOL: + return "false" + case descriptor.FieldDescriptorProto_TYPE_STRING: + return "\"\"" + case descriptor.FieldDescriptorProto_TYPE_MESSAGE: + return nilString + case descriptor.FieldDescriptorProto_TYPE_BYTES: + return "0" + case descriptor.FieldDescriptorProto_TYPE_ENUM: + return nilString + default: + return nilString + } +} + +func jsType(f *descriptor.FieldDescriptorProto) string { + template := "%s" + if isFieldRepeated(f) { + template = "Array<%s>" + } + + switch *f.Type { + case descriptor.FieldDescriptorProto_TYPE_MESSAGE, + descriptor.FieldDescriptorProto_TYPE_ENUM: + return fmt.Sprintf(template, namespacedFlowType(*f.TypeName)) + case descriptor.FieldDescriptorProto_TYPE_DOUBLE, + descriptor.FieldDescriptorProto_TYPE_FLOAT, + descriptor.FieldDescriptorProto_TYPE_INT64, + descriptor.FieldDescriptorProto_TYPE_UINT64, + descriptor.FieldDescriptorProto_TYPE_INT32, + descriptor.FieldDescriptorProto_TYPE_FIXED64, + descriptor.FieldDescriptorProto_TYPE_FIXED32, + descriptor.FieldDescriptorProto_TYPE_UINT32, + descriptor.FieldDescriptorProto_TYPE_SFIXED32, + descriptor.FieldDescriptorProto_TYPE_SFIXED64, + descriptor.FieldDescriptorProto_TYPE_SINT32, + descriptor.FieldDescriptorProto_TYPE_SINT64: + return fmt.Sprintf(template, "number") + case descriptor.FieldDescriptorProto_TYPE_BOOL: + return fmt.Sprintf(template, "boolean") + case descriptor.FieldDescriptorProto_TYPE_BYTES: + return fmt.Sprintf(template, "Uint8Array") + case descriptor.FieldDescriptorProto_TYPE_STRING: + return fmt.Sprintf(template, "string") + default: + return fmt.Sprintf(template, "any") + } +} + +func jsSuffixReservedKeyword(s string) string { + return jsReservedRe.ReplaceAllString(s, "${1}${2}_${3}") +} + +func isTimestampPackage(s string) bool { + var isTimestampPackage bool + if strings.Compare(s, ".google.protobuf.Timestamp") == 0 { + isTimestampPackage = true + } + return isTimestampPackage +} + +func getPackageTypeName(s string) string { + if strings.Contains(s, ".") { + return strings.Split(s, ".")[1] + } + return "" +} + +func shortType(s string) string { + t := strings.Split(s, ".") + return t[len(t)-1] +} + +func namespacedFlowType(s string) string { + trimmed := strings.TrimLeft(s, ".") + splitted := strings.Split(trimmed, ".") + return strings.Join(splitted, "$") +} + +func httpPath(m *descriptor.MethodDescriptorProto) string { + + ext, err := proto.GetExtension(m.Options, options.E_Http) + if err != nil { + return err.Error() + } + opts, ok := ext.(*options.HttpRule) + if !ok { + return fmt.Sprintf("extension is %T; want an HttpRule", ext) + } + + switch t := opts.Pattern.(type) { + default: + return "" + case *options.HttpRule_Get: + return t.Get + case *options.HttpRule_Post: + return t.Post + case *options.HttpRule_Put: + return t.Put + case *options.HttpRule_Delete: + return t.Delete + case *options.HttpRule_Patch: + return t.Patch + case *options.HttpRule_Custom: + return t.Custom.Path + } +} + +func httpPathsAdditionalBindings(m *descriptor.MethodDescriptorProto) []string { + ext, err := proto.GetExtension(m.Options, options.E_Http) + if err != nil { + panic(err.Error()) + } + opts, ok := ext.(*options.HttpRule) + if !ok { + panic(fmt.Sprintf("extension is %T; want an HttpRule", ext)) + } + + var httpPaths []string + var optsAdditionalBindings = opts.GetAdditionalBindings() + for _, optAdditionalBindings := range optsAdditionalBindings { + switch t := optAdditionalBindings.Pattern.(type) { + case *options.HttpRule_Get: + httpPaths = append(httpPaths, t.Get) + case *options.HttpRule_Post: + httpPaths = append(httpPaths, t.Post) + case *options.HttpRule_Put: + httpPaths = append(httpPaths, t.Put) + case *options.HttpRule_Delete: + httpPaths = append(httpPaths, t.Delete) + case *options.HttpRule_Patch: + httpPaths = append(httpPaths, t.Patch) + case *options.HttpRule_Custom: + httpPaths = append(httpPaths, t.Custom.Path) + default: + // nothing + } + } + + return httpPaths +} + +func openapiOption(m *descriptor.MethodDescriptorProto) *openapi_options.Operation { + + ext, err := proto.GetExtension(m.Options, openapi_options.E_Openapiv2Operation) + if err != nil { + return nil + } + opts, ok := ext.(*openapi_options.Operation) + if !ok { + panic(fmt.Sprintf("extension is %T; want an Openapiv2Operation", ext)) + } + + return opts +} + +func httpOption(m *descriptor.MethodDescriptorProto) *HttpOption { + + ext, err := proto.GetExtension(m.Options, options.E_Http) + if err != nil { + return nil + } + hr, ok := ext.(*options.HttpRule) + if !ok { + panic(fmt.Sprintf("extension is %T; want an HttpRule", ext)) + } + + var method string + var path string + switch t := hr.Pattern.(type) { + default: + break + case *options.HttpRule_Get: + method = "GET" + path = t.Get + case *options.HttpRule_Post: + method = "POST" + path = t.Post + case *options.HttpRule_Put: + method = "PUT" + path = t.Put + case *options.HttpRule_Delete: + method = "DELETE" + path = t.Delete + case *options.HttpRule_Patch: + method = "PATCH" + path = t.Patch + case *options.HttpRule_Custom: + method = t.Custom.Kind + path = t.Custom.Path + } + + opt := &HttpOption{Method: method, Body: hr.Body, Path: path} + + for _, ahr := range hr.AdditionalBindings { + switch t := ahr.Pattern.(type) { + default: + break + case *options.HttpRule_Get: + method = "GET" + path = t.Get + case *options.HttpRule_Post: + method = "POST" + path = t.Post + case *options.HttpRule_Put: + method = "PUT" + path = t.Put + case *options.HttpRule_Delete: + method = "DELETE" + path = t.Delete + case *options.HttpRule_Patch: + method = "PATCH" + path = t.Patch + case *options.HttpRule_Custom: + method = t.Custom.Kind + path = t.Custom.Path + } + + aopt := &HttpOption{Method: method, Body: ahr.Body, Path: path} + opt.Additional = append(opt.Additional, aopt) + } + + return opt +} + +func httpVerb(m *descriptor.MethodDescriptorProto) string { + + ext, err := proto.GetExtension(m.Options, options.E_Http) + if err != nil { + return err.Error() + } + opts, ok := ext.(*options.HttpRule) + if !ok { + return fmt.Sprintf("extension is %T; want an HttpRule", ext) + } + + switch t := opts.Pattern.(type) { + default: + return "" + case *options.HttpRule_Get: + return "GET" + case *options.HttpRule_Post: + return "POST" + case *options.HttpRule_Put: + return "PUT" + case *options.HttpRule_Delete: + return "DELETE" + case *options.HttpRule_Patch: + return "PATCH" + case *options.HttpRule_Custom: + return t.Custom.Kind + } +} + +func httpBody(m *descriptor.MethodDescriptorProto) string { + + ext, err := proto.GetExtension(m.Options, options.E_Http) + if err != nil { + return err.Error() + } + opts, ok := ext.(*options.HttpRule) + if !ok { + return fmt.Sprintf("extension is %T; want an HttpRule", ext) + } + return opts.Body +} + +func urlVarsFields(path string, d *ggdescriptor.Message) []*descriptor.FieldDescriptorProto { + var vars []*descriptor.FieldDescriptorProto + for _, field := range d.Field { + if !isFieldMessage(field) { + if strings.Contains(path, fmt.Sprintf("{%s}", *field.Name)) { + vars = append(vars, field) + continue + } + // JSON name field is checked as fallback. The value set by the protocol compiler. + // If the user has set a "json_name" option on a field, that option's value + // will be used in this check. By default value in this property will be field name in + // camelCase format. + if strings.Contains(path, fmt.Sprintf("{%s}", *field.JsonName)) { + vars = append(vars, field) + } + } + } + return vars +} + +func urlHasVarsFromMessage(path string, d *ggdescriptor.Message) bool { + for _, field := range d.Field { + if !isFieldMessage(field) { + if strings.Contains(path, fmt.Sprintf("{%s}", *field.Name)) { + return true + } + // JSON name field is checked as fallback. The value set by the protocol compiler. + // If the user has set a "json_name" option on a field, that option's value + // will be used in this check. By default value in this property will be field name in + // camelCase format. + if strings.Contains(path, fmt.Sprintf("{%s}", *field.JsonName)) { + return true + } + } + } + return false +} + +// lowerGoNormalize takes a string and applies formatting +// rules to conform to Golang convention. It applies a camel +// case filter, lowers the first character and formats fields +// with `id` to `ID`. +func lowerGoNormalize(s string) string { + fmtd := xstrings.ToCamelCase(s) + fmtd = xstrings.FirstRuneToLower(fmtd) + return formatID(s, fmtd) +} + +// goNormalize takes a string and applies formatting rules +// to conform to Golang convention. It applies a camel case +// filter and formats fields with `id` to `ID`. +func goNormalize(s string) string { + fmtd := xstrings.ToCamelCase(s) + return formatID(s, fmtd) +} + +// formatID takes a base string alonsgide a formatted string. +// It acts as a transformation filter for fields containing +// `id` in order to conform to Golang convention. +func formatID(base string, formatted string) string { + if formatted == "" { + return formatted + } + switch { + case base == "id": + // id -> ID + return "ID" + case strings.HasPrefix(base, "id_"): + // id_some -> IDSome + return "ID" + formatted[2:] + case strings.HasSuffix(base, "_id"): + // some_id -> SomeID + return formatted[:len(formatted)-2] + "ID" + case strings.HasSuffix(base, "_ids"): + // some_ids -> SomeIDs + return formatted[:len(formatted)-3] + "IDs" + } + return formatted +} + +func replaceDict(src string, dict map[string]interface{}) string { + for old, v := range dict { + n, ok := v.(string) + if !ok { + continue + } + src = strings.Replace(src, old, n, -1) + } + return src +} + +func goPkg(f *descriptor.FileDescriptorProto) string { + if name := f.Options.GetGoPackage(); name != "" { + return name + } + return f.GetPackage() +} + +func goPkgLastElement(f *descriptor.FileDescriptorProto) string { + pkg := goPkg(f) + pkgSplitted := strings.Split(pkg, "/") + return pkgSplitted[len(pkgSplitted)-1] +} diff --git a/http.go b/http.go deleted file mode 100644 index 68fb791..0000000 --- a/http.go +++ /dev/null @@ -1,55 +0,0 @@ -package main - -import ( - "google.golang.org/protobuf/compiler/protogen" -) - -func (g *Generator) httpGenerate(component string, plugin *protogen.Plugin, genClient bool, genServer bool) error { - for _, file := range plugin.Files { - if !file.Generate { - continue - } - if len(file.Services) == 0 { - continue - } - - gname := file.GeneratedFilenamePrefix + "_micro_" + component + ".pb.go" - path := file.GoImportPath - if g.standalone { - path = "." - } - gfile := plugin.NewGeneratedFile(gname, path) - - gfile.P("// Code generated by protoc-gen-go-micro. DO NOT EDIT.") - gfile.P("// protoc-gen-go-micro version: " + versionComment) - gfile.P("// source: ", file.Proto.GetName()) - gfile.P() - gfile.P("package ", file.GoPackageName) - gfile.P() - - gfile.Import(contextPackage) - - if genClient { - gfile.Import(microClientPackage) - gfile.Import(microClientHttpPackage) - } - if genServer { - gfile.Import(microServerPackage) - } - - for _, service := range file.Services { - g.generateServiceEndpoints(gfile, service, component) - if genClient { - g.generateServiceClient(gfile, file, service) - g.generateServiceClientMethods(gfile, service, component) - } - if genServer { - g.generateServiceServer(gfile, file, service) - g.generateServiceServerMethods(gfile, service) - g.generateServiceRegister(gfile, file, service, component) - } - } - } - - return nil -} diff --git a/main.go b/main.go index 71a52f0..f00b409 100644 --- a/main.go +++ b/main.go @@ -1,130 +1,217 @@ package main import ( - "flag" "fmt" + "go/format" + "io/ioutil" + "log" + "net/url" "os" "strings" - "google.golang.org/protobuf/compiler/protogen" - "google.golang.org/protobuf/types/pluginpb" + "github.com/golang/protobuf/protoc-gen-go/generator" + plugin_go "github.com/golang/protobuf/protoc-gen-go/plugin" + ggdescriptor "github.com/grpc-ecosystem/grpc-gateway/protoc-gen-grpc-gateway/descriptor" + pgghelpers "github.com/unistack-org/protoc-gen-micro/v3/helpers" + "google.golang.org/protobuf/proto" ) var ( - flagSet = flag.NewFlagSet(os.Args[0], flag.ExitOnError) - flagDebug = flagSet.Bool("debug", false, "debug output") - flagStandalone = flagSet.Bool("standalone", false, "generate file to standalone dir") - flagFieldaligment = flagSet.Bool("fieldaligment", false, "align struct fields in generated code") - flagComponents = flagSet.String("components", "micro|rpc|http|client|server|openapiv3", "specify components to generate") - flagTagPath = flagSet.String("tag_path", "", "tag rewriting dir") - flagOpenapiFile = flagSet.String("openapi_file", "apidocs.swagger.json", "openapi file name") - flagReflection = flagSet.Bool("reflection", false, "enable server reflection support") - flagHelp = flagSet.Bool("help", false, "display help message") + registry *ggdescriptor.Registry // some helpers need access to registry +) + +const ( + boolTrue = "true" + boolFalse = "false" +) + +var ( + templateDir = "" + templateRepo = "" + destinationDir = "." + debug = false + all = false + singlePackageMode = false + fileMode = false + components = []string{"micro", "grpc"} ) func main() { - opts := &protogen.Options{ - ParamFunc: flagSet.Set, + g := generator.New() + + data, err := ioutil.ReadAll(os.Stdin) + if err != nil { + g.Error(err, "reading input") } - flagSet.Parse(os.Args[1:]) - - if *flagHelp { - flagSet.PrintDefaults() - return + if err = proto.Unmarshal(data, g.Request); err != nil { + g.Error(err, "parsing input proto") } - g := &Generator{} - - opts.Run(g.Generate) -} - -type Generator struct { - components string - standalone bool - debug bool - fieldaligment bool - tagPath string - openapiFile string - reflection bool - plugin *protogen.Plugin -} - -func (g *Generator) Generate(plugin *protogen.Plugin) error { - var err error - - g.plugin = plugin - g.standalone = *flagStandalone - g.debug = *flagDebug - g.components = *flagComponents - g.fieldaligment = *flagFieldaligment - g.tagPath = *flagTagPath - g.openapiFile = *flagOpenapiFile - g.reflection = *flagReflection - plugin.SupportedFeatures = uint64(pluginpb.CodeGeneratorResponse_FEATURE_PROTO3_OPTIONAL) - - var genClient bool - var genServer bool - var genNone bool - - if strings.Contains(g.components, "server") { - genServer = true - } - if strings.Contains(g.components, "client") { - genClient = true - } - if strings.Contains(g.components, "none") { - genNone = true - } - if strings.Contains(g.components, "rpc") || strings.Contains(g.components, "http") { - if !genServer && !genClient && !genNone { - genServer = true - genClient = true - } + if len(g.Request.FileToGenerate) == 0 { + g.Fail("no files to generate") } - // Protoc passes a slice of File structs for us to process - for _, component := range strings.Split(g.components, "|") { - switch component { - case "server", "client": - continue - case "micro": - err = g.microGenerate(component, plugin, genClient, genServer) - if err == nil { - err = g.writeErrors(plugin) + g.CommandLineParameters(g.Request.GetParameter()) + + // Parse parameters + if parameter := g.Request.GetParameter(); parameter != "" { + for _, param := range strings.Split(parameter, ",") { + parts := strings.Split(param, "=") + switch parts[0] { + case "template_dir": + templateDir = parts[1] + case "destination_dir": + destinationDir = parts[1] + case "single-package-mode": + switch strings.ToLower(parts[1]) { + case boolTrue, "t": + singlePackageMode = true + case boolFalse, "f": + default: + log.Printf("Err: invalid value for single-package-mode: %q", parts[1]) + } + case "debug": + switch strings.ToLower(parts[1]) { + case boolTrue, "t": + debug = true + case boolFalse, "f": + default: + log.Printf("Err: invalid value for debug: %q", parts[1]) + } + case "all": + switch strings.ToLower(parts[1]) { + case boolTrue, "t": + all = true + case boolFalse, "f": + default: + log.Printf("Err: invalid value for debug: %q", parts[1]) + } + case "file-mode": + switch strings.ToLower(parts[1]) { + case boolTrue, "t": + fileMode = true + case boolFalse, "f": + default: + log.Printf("Err: invalid value for file-mode: %q", parts[1]) + } + case "template_repo": + _, err := url.Parse(parts[1]) + if err != nil { + log.Printf("Err: invalid value for template_repo: %q", parts[1]) + } + templateRepo = parts[1] + case "components": + _, err := url.Parse(parts[1]) + if err != nil { + log.Printf("Err: invalid value for components: %q", parts[1]) + } + components = strings.Split(parts[1], "|") + case "paths": + // TODO: handle paths=source_relative + default: + log.Printf("Err: unknown parameter: %q", param) } - case "http": - err = g.httpGenerate(component, plugin, genClient, genServer) - case "grpc", "drpc", "rpc": - err = g.rpcGenerate(component, plugin, genClient, genServer) - case "gorilla": - err = g.gorillaGenerate(component, plugin) - case "chi": - err = g.chiGenerate(component, plugin) - case "openapiv3": - err = g.openapiv3Generate(component, plugin) - case "none": - break - default: - err = fmt.Errorf("unknown component: %s", component) + } + } + + tmplMap := make(map[string]*plugin_go.CodeGeneratorResponse_File) + concatOrAppend := func(file *plugin_go.CodeGeneratorResponse_File) { + if val, ok := tmplMap[file.GetName()]; ok { + *val.Content += file.GetContent() + } else { + tmplMap[file.GetName()] = file + g.Response.File = append(g.Response.File, file) + } + } + + if singlePackageMode { + registry = ggdescriptor.NewRegistry() + pgghelpers.SetRegistry(registry) + if err = registry.Load(g.Request); err != nil { + g.Error(err, "registry: failed to load the request") + } + } + + if templateDir == "" && templateRepo != "" { + if templateDir, err = ioutil.TempDir("", "gen-*"); err != nil { + g.Error(err, "failed to create tmp dir") + } + defer func() { + if err := os.RemoveAll(templateDir); err != nil { + g.Error(err, "failed to remove tmp dir") + } + }() + + if templateRepo != "" { + if err = clone(templateRepo, templateDir); err != nil { + g.Error(err, "failed to clone repo") + } + } + } + + filesToGenerate := map[string]struct{}{} + for _, file := range g.Request.FileToGenerate { + filesToGenerate[file] = struct{}{} + } + + // Generate the encoders + for _, file := range g.Request.GetProtoFile() { + // Ignore files not in g.Request.FileToGenerate. + if _, ok := filesToGenerate[*file.Name]; !ok { + continue + } + if all { + if singlePackageMode { + if _, err = registry.LookupFile(file.GetName()); err != nil { + g.Error(err, "registry: failed to lookup file %q", file.GetName()) + } + } + encoder := NewGenericTemplateBasedEncoder(templateDir, file, debug, destinationDir) + for _, tmpl := range encoder.Files() { + concatOrAppend(tmpl) + } + + continue } + if fileMode { + if s := file.GetService(); s != nil && len(s) > 0 { + encoder := NewGenericTemplateBasedEncoder(templateDir, file, debug, destinationDir) + for _, tmpl := range encoder.Files() { + concatOrAppend(tmpl) + } + } + + continue + } + + for _, service := range file.GetService() { + encoder := NewGenericServiceTemplateBasedEncoder(templateDir, service, file, debug, destinationDir) + for _, tmpl := range encoder.Files() { + concatOrAppend(tmpl) + } + } + } + + // Generate the protobufs + g.GenerateAllFiles() + + for _, f := range g.Response.File { + fdata, err := format.Source([]byte(*f.Content)) if err != nil { - plugin.Error(err) - return err + g.Error(err, fmt.Sprintf("failed to format output: %s", *f.Content)) } - + *f.Content = string(fdata) } - if err = g.astGenerate(plugin); err != nil { - plugin.Error(err) - return err + data, err = proto.Marshal(g.Response) + if err != nil { + g.Error(err, "failed to marshal output proto") } - if err = g.fieldAlign(plugin); err != nil { - plugin.Error(err) - return err + _, err = os.Stdout.Write(data) + if err != nil { + g.Error(err, "failed to write output proto") } - - return nil } diff --git a/micro.go b/micro.go deleted file mode 100644 index 762e375..0000000 --- a/micro.go +++ /dev/null @@ -1,68 +0,0 @@ -package main - -import ( - "fmt" - - "google.golang.org/protobuf/compiler/protogen" -) - -func (g *Generator) microGenerate(component string, plugin *protogen.Plugin, genClient bool, genServer bool) error { - for _, file := range plugin.Files { - if !file.Generate { - continue - } - if len(file.Services) == 0 { - continue - } - - gname := file.GeneratedFilenamePrefix + "_" + component + ".pb.go" - - path := file.GoImportPath - if g.standalone { - path = "." - } - gfile := plugin.NewGeneratedFile(gname, path) - - gfile.P("// Code generated by protoc-gen-go-micro. DO NOT EDIT.") - gfile.P("// versions:") - gfile.P("// - protoc-gen-go-micro " + versionComment) - gfile.P("// - protoc ", protocVersion(plugin)) - gfile.P("// source: ", file.Desc.Path()) - gfile.P() - gfile.P("package ", file.GoPackageName) - gfile.P() - - gfile.Import(contextPackage) - - if genClient { - gfile.Import(microClientPackage) - } - // generate services - for _, service := range file.Services { - g.generateServiceName(gfile, service) - if genClient { - g.generateServiceClientInterface(gfile, service) - g.generateServiceClientStreamInterface(gfile, service) - } - if genServer { - g.generateServiceServerInterface(gfile, service) - g.generateServiceServerStreamInterface(gfile, service) - } - } - - } - - return nil -} - -func protocVersion(plugin *protogen.Plugin) string { - v := plugin.Request.GetCompilerVersion() - if v == nil { - return "(unknown)" - } - var suffix string - if s := v.GetSuffix(); s != "" { - suffix = "-" + s - } - return fmt.Sprintf("v%d.%d.%d%s", v.GetMajor(), v.GetMinor(), v.GetPatch(), suffix) -} diff --git a/openapiv3.go b/openapiv3.go deleted file mode 100644 index 7c40927..0000000 --- a/openapiv3.go +++ /dev/null @@ -1,1207 +0,0 @@ -// Copyright 2020 Google LLC. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -package main - -import ( - "fmt" - "log" - "net/url" - "regexp" - "sort" - "strings" - "sync" - - "go.unistack.org/micro-proto/v4/api" - v3 "go.unistack.org/micro-proto/v4/openapiv3" - "google.golang.org/protobuf/compiler/protogen" - "google.golang.org/protobuf/proto" - "google.golang.org/protobuf/reflect/protoreflect" - "google.golang.org/protobuf/reflect/protoregistry" -) - -const ( - protobufValueName = "AnyJSONValue" -) - -// openapiv3Generator holds internal state needed to generate an OpenAPIv3 document for a transcoded Protocol Buffer service. -type openapiv3Generator struct { - circularDepth int - naming string - plugin *protogen.Plugin - requiredSchemas []string // Names of schemas that need to be generated. - generatedSchemas []string // Names of schemas that have already been generated. - linterRulePattern *regexp.Regexp - pathPattern *regexp.Regexp - namedPathPattern *regexp.Regexp -} - -var ( - once sync.Once - protofiles = &protoregistry.Files{} -) - -func protofilesAdd(plugin *protogen.Plugin) { - for path, f := range plugin.FilesByPath { - if _, err := protofiles.FindFileByPath(path); err != nil { - protofiles.RegisterFile(f.Desc) - } - } -} - -// openapiv3Generate creates a new generator for a protoc plugin invocation. -func (g *Generator) openapiv3Generate(component string, plugin *protogen.Plugin) error { - og := &openapiv3Generator{ - circularDepth: 2, - plugin: plugin, - naming: "proto", - - requiredSchemas: make([]string, 0), - generatedSchemas: make([]string, 0), - linterRulePattern: regexp.MustCompile(`\(-- .* --\)`), - pathPattern: regexp.MustCompile("{([^=}]+)}"), - namedPathPattern: regexp.MustCompile("{(.+)=(.+)}"), - } - - protofilesAdd(plugin) - - d := og.buildDocumentV3(plugin) - bytes, err := d.YAMLValue("Generated with protoc-gen-go-micro\n") - if err != nil { - return fmt.Errorf("failed to marshal yaml: %s", err.Error()) - } - outputFile := og.plugin.NewGeneratedFile(g.openapiFile, "") - if _, err := outputFile.Write(bytes); err != nil { - return fmt.Errorf("failed to write: %s", err.Error()) - } - - return nil -} - -// buildDocumentV3 builds an OpenAPIv3 document for a plugin request. -func (g *openapiv3Generator) buildDocumentV3(plugin *protogen.Plugin) *v3.Document { - d := &v3.Document{Openapi: "3.0.3", Info: &v3.Info{Version: "0.0.1"}} - - for _, file := range plugin.Files { - if !proto.HasExtension(file.Desc.Options(), v3.E_Openapiv3Swagger) { - continue - } - - ext := proto.GetExtension(file.Desc.Options(), v3.E_Openapiv3Swagger) - if ext == nil { - continue - } - - if doc, ok := ext.(*v3.Document); ok && doc != nil { - if doc.Openapi != "" { - d.Openapi = doc.Openapi - } - if doc.Info != nil { - d.Info = proto.Clone(doc.Info).(*v3.Info) - } - d.Servers = append(d.Servers, doc.Servers...) - } - - } - - d.Paths = &v3.Paths{} - d.Components = &v3.Components{ - Schemas: &v3.SchemasOrReferences{ - AdditionalProperties: []*v3.NamedSchemaOrReference{}, - }, - } - - for _, file := range g.plugin.Files { - if file.Generate { - g.addPathsToDocumentV3(d, file) - } - } - - // If there is only 1 service, then use it's title for the document, - // if the document is missing it. - if len(d.Tags) == 1 { - if d.Info.Title == "" && d.Tags[0].Name != "" { - d.Info.Title = d.Tags[0].Name + " API" - } - if d.Info.Description == "" { - d.Info.Description = d.Tags[0].Description - } - d.Tags[0].Description = "" - } - - for len(g.requiredSchemas) > 0 { - count := len(g.requiredSchemas) - for _, file := range g.plugin.Files { - g.addSchemasToDocumentV3(d, file.Messages) - } - g.requiredSchemas = g.requiredSchemas[count:len(g.requiredSchemas)] - } - - allServers := []string{} - - // If paths methods has servers, but they're all the same, then move servers to path level - for _, path := range d.Paths.Path { - servers := []string{} - // Only 1 server will ever be set, per method, by the generator - - if path.Value.Get != nil && len(path.Value.Get.Servers) == 1 { - servers = appendUniuqe(servers, path.Value.Get.Servers[0].Url) - allServers = appendUniuqe(servers, path.Value.Get.Servers[0].Url) - } - if path.Value.Post != nil && len(path.Value.Post.Servers) == 1 { - servers = appendUniuqe(servers, path.Value.Post.Servers[0].Url) - allServers = appendUniuqe(servers, path.Value.Post.Servers[0].Url) - } - if path.Value.Put != nil && len(path.Value.Put.Servers) == 1 { - servers = appendUniuqe(servers, path.Value.Put.Servers[0].Url) - allServers = appendUniuqe(servers, path.Value.Put.Servers[0].Url) - } - if path.Value.Delete != nil && len(path.Value.Delete.Servers) == 1 { - servers = appendUniuqe(servers, path.Value.Delete.Servers[0].Url) - allServers = appendUniuqe(servers, path.Value.Delete.Servers[0].Url) - } - if path.Value.Patch != nil && len(path.Value.Patch.Servers) == 1 { - servers = appendUniuqe(servers, path.Value.Patch.Servers[0].Url) - allServers = appendUniuqe(servers, path.Value.Patch.Servers[0].Url) - } - - if len(servers) == 1 { - path.Value.Servers = []*v3.Server{{Url: servers[0]}} - - if path.Value.Get != nil { - path.Value.Get.Servers = nil - } - if path.Value.Post != nil { - path.Value.Post.Servers = nil - } - if path.Value.Put != nil { - path.Value.Put.Servers = nil - } - if path.Value.Delete != nil { - path.Value.Delete.Servers = nil - } - if path.Value.Patch != nil { - path.Value.Patch.Servers = nil - } - } - } - - // Set all servers on API level - if len(allServers) > 0 { - d.Servers = []*v3.Server{} - for _, server := range allServers { - d.Servers = append(d.Servers, &v3.Server{Url: server}) - } - } - - // If there is only 1 server, we can safely remove all path level servers - if len(allServers) == 1 { - for _, path := range d.Paths.Path { - path.Value.Servers = nil - } - } - - // Sort the tags. - { - pairs := d.Tags - sort.Slice(pairs, func(i, j int) bool { - return pairs[i].Name < pairs[j].Name - }) - d.Tags = pairs - } - // Sort the paths. - { - pairs := d.Paths.Path - sort.Slice(pairs, func(i, j int) bool { - return pairs[i].Name < pairs[j].Name - }) - d.Paths.Path = pairs - } - // Sort the schemas. - { - pairs := d.Components.Schemas.AdditionalProperties - sort.Slice(pairs, func(i, j int) bool { - return pairs[i].Name < pairs[j].Name - }) - d.Components.Schemas.AdditionalProperties = pairs - } - return d -} - -// filterCommentString removes line breaks and linter rules from comments. -func (g *openapiv3Generator) filterCommentString(c protogen.Comments, removeNewLines bool) string { - comment := string(c) - if removeNewLines { - comment = strings.Replace(comment, "\n", "", -1) - } - comment = g.linterRulePattern.ReplaceAllString(comment, "") - return strings.TrimSpace(comment) -} - -// addPathsToDocumentV3 adds paths from a specified file descriptor. -func (g *openapiv3Generator) addPathsToDocumentV3(d *v3.Document, file *protogen.File) { - for _, service := range file.Services { - annotationsCount := 0 - - for _, method := range service.Methods { - comment := g.filterCommentString(method.Comments.Leading, false) - inputMessage := method.Input - outputMessage := method.Output - operationID := service.GoName + "_" + method.GoName - - e3opt := proto.GetExtension(method.Desc.Options(), v3.E_Openapiv3Operation) - if e3opt != nil && e3opt != v3.E_Openapiv3Operation.InterfaceOf(v3.E_Openapiv3Operation.Zero()) { - if opt, ok := e3opt.(*v3.Operation); ok && opt.OperationId != "" { - operationID = opt.OperationId - } - } - - var path string - var methodName string - var body string - - extHTTP := proto.GetExtension(method.Desc.Options(), api.E_Http) - if extHTTP != nil && extHTTP != api.E_Http.InterfaceOf(api.E_Http.Zero()) { - annotationsCount++ - - rule := extHTTP.(*api.HttpRule) - body = rule.Body - switch pattern := rule.Pattern.(type) { - case *api.HttpRule_Get: - path = pattern.Get - methodName = "GET" - case *api.HttpRule_Post: - path = pattern.Post - methodName = "POST" - case *api.HttpRule_Put: - path = pattern.Put - methodName = "PUT" - case *api.HttpRule_Delete: - path = pattern.Delete - methodName = "DELETE" - case *api.HttpRule_Patch: - path = pattern.Patch - methodName = "PATCH" - case *api.HttpRule_Custom: - path = "custom-unsupported" - default: - path = "unknown-unsupported" - } - } - - if methodName != "" { - defaultHost := proto.GetExtension(service.Desc.Options(), api.E_DefaultHost).(string) - - op, path2 := g.buildOperationV3( - file, method, operationID, service.GoName, comment, defaultHost, path, body, inputMessage, outputMessage) - g.addOperationV3(d, op, path2, methodName) - } - } - - if annotationsCount > 0 { - comment := g.filterCommentString(service.Comments.Leading, false) - d.Tags = append(d.Tags, &v3.Tag{Name: service.GoName, Description: comment}) - } - } -} - -func (g *openapiv3Generator) formatMessageRef(name string) string { - if g.naming == "proto" { - return name - } - - if len(name) > 1 { - return strings.ToUpper(name[0:1]) + name[1:] - } - - if len(name) == 1 { - return strings.ToLower(name) - } - - return name -} - -func (g *openapiv3Generator) getMessageName(message protoreflect.MessageDescriptor) string { - prefix := "" - parent := message.Parent() - if message != nil { - if _, ok := parent.(protoreflect.MessageDescriptor); ok { - prefix = string(parent.Name()) + "_" + prefix - } - } - - return prefix + string(message.Name()) -} - -func (g *openapiv3Generator) formatMessageName(message *protogen.Message) string { - name := g.getMessageName(message.Desc) - - if g.naming == "proto" { - return name - } - - if len(name) > 0 { - return strings.ToUpper(name[0:1]) + name[1:] - } - - return name -} - -func (g *openapiv3Generator) formatFieldName(field *protogen.Field) string { - if g.naming == "proto" { - return string(field.Desc.Name()) - } - - return field.Desc.JSONName() -} - -func (g *openapiv3Generator) findField(name string, inMessage *protogen.Message) *protogen.Field { - for _, field := range inMessage.Fields { - if string(field.Desc.Name()) == name || string(field.Desc.JSONName()) == name { - return field - } - } - - return nil -} - -func (g *openapiv3Generator) findAndFormatFieldName(name string, inMessage *protogen.Message) string { - field := g.findField(name, inMessage) - if field != nil { - return g.formatFieldName(field) - } - - return name -} - -// Note that fields which are mapped to URL query parameters must have a primitive type -// or a repeated primitive type or a non-repeated message type. -// In the case of a repeated type, the parameter can be repeated in the URL as ...?param=A¶m=B. -// In the case of a message type, each field of the message is mapped to a separate parameter, -// such as ...?foo.a=A&foo.b=B&foo.c=C. -// -// maps, Struct and Empty can NOT be used -// messages can have any number of sub messages - including circular (e.g. sub.subsub.sub.subsub.id) - -// buildQueryParamsV3 extracts any valid query params, including sub and recursive messages -func (g *openapiv3Generator) buildQueryParamsV3(field *protogen.Field) []*v3.ParameterOrReference { - depths := map[string]int{} - return g._buildQueryParamsV3(field, depths) -} - -// depths are used to keep track of how many times a message's fields has been seen -func (g *openapiv3Generator) _buildQueryParamsV3(field *protogen.Field, depths map[string]int) []*v3.ParameterOrReference { - parameters := []*v3.ParameterOrReference{} - - queryFieldName := g.formatFieldName(field) - fieldDescription := g.filterCommentString(field.Comments.Leading, true) - - if field.Desc.IsMap() { - // Map types are not allowed in query parameteres - return parameters - } else if field.Desc.Kind() == protoreflect.MessageKind { - // Represent google.protobuf.Value as reference to the value of const protobufValueName. - if g.fullMessageTypeName(field.Desc.Message()) == ".google.protobuf.Value" { - fieldSchema := g.schemaOrReferenceForField(field.Desc) - parameters = append(parameters, - &v3.ParameterOrReference{ - Oneof: &v3.ParameterOrReference_Parameter{ - Parameter: &v3.Parameter{ - Name: queryFieldName, - In: "query", - Description: fieldDescription, - Required: false, - Schema: fieldSchema, - }, - }, - }) - return parameters - } else if field.Desc.IsList() { - // Only non-repeated message types are valid - return parameters - } - - // Represent field masks directly as strings (don't expand them). - if g.fullMessageTypeName(field.Desc.Message()) == ".google.protobuf.FieldMask" { - fieldSchema := g.schemaOrReferenceForField(field.Desc) - parameters = append(parameters, - &v3.ParameterOrReference{ - Oneof: &v3.ParameterOrReference_Parameter{ - Parameter: &v3.Parameter{ - Name: queryFieldName, - In: "query", - Description: fieldDescription, - Required: false, - Schema: fieldSchema, - }, - }, - }) - return parameters - } - - // Sub messages are allowed, even circular, as long as the final type is a primitive. - // Go through each of the sub message fields - for _, subField := range field.Message.Fields { - subFieldFullName := string(subField.Desc.FullName()) - seen, ok := depths[subFieldFullName] - if !ok { - depths[subFieldFullName] = 0 - } - - if seen < g.circularDepth { - depths[subFieldFullName]++ - subParams := g._buildQueryParamsV3(subField, depths) - for _, subParam := range subParams { - if param, ok := subParam.Oneof.(*v3.ParameterOrReference_Parameter); ok { - param.Parameter.Name = queryFieldName + "." + param.Parameter.Name - parameters = append(parameters, subParam) - } - } - } - } - - } else if field.Desc.Kind() != protoreflect.GroupKind { - // schemaOrReferenceForField also handles array types - fieldSchema := g.schemaOrReferenceForField(field.Desc) - - parameters = append(parameters, - &v3.ParameterOrReference{ - Oneof: &v3.ParameterOrReference_Parameter{ - Parameter: &v3.Parameter{ - Name: queryFieldName, - In: "query", - Description: fieldDescription, - Required: false, - Schema: fieldSchema, - }, - }, - }) - } - - return parameters -} - -// buildOperationV3 constructs an operation for a set of values. -func (g *openapiv3Generator) buildOperationV3( - file *protogen.File, - method *protogen.Method, - operationID string, - tagName string, - description string, - defaultHost string, - path string, - bodyField string, - inputMessage *protogen.Message, - outputMessage *protogen.Message, -) (*v3.Operation, string) { - // coveredParameters tracks the parameters that have been used in the body or path. - coveredParameters := make([]string, 0) - if bodyField != "" { - coveredParameters = append(coveredParameters, bodyField) - } - // Initialize the list of operation parameters. - parameters := []*v3.ParameterOrReference{} - - // Build a list of header parameters. - eopt := proto.GetExtension(method.Desc.Options(), v3.E_Openapiv3Operation) - if eopt != nil && eopt != v3.E_Openapiv3Operation.InterfaceOf(v3.E_Openapiv3Operation.Zero()) { - opt := eopt.(*v3.Operation) - parameters = append(parameters, opt.Parameters...) - } - - sparameters := make(map[string]struct{}) - for _, paramOrRef := range parameters { - parameter := paramOrRef.GetParameter() - if parameter == nil { - continue - } - sparameters[parameter.Name] = struct{}{} - } - - if u, err := url.Parse(path); err == nil { - mp := u.Query() - path = u.Path - if mp != nil { - for _, field := range inputMessage.Fields { - fieldName := string(field.Desc.Name()) - if _, ok := mp[fieldName]; ok && fieldName != bodyField { - fieldParams := g.buildQueryParamsV3(field) - parameters = append(parameters, fieldParams...) - coveredParameters = append(coveredParameters, fieldName) - } - } - } - } - - // Find simple path parameters like {id} - if allMatches := g.pathPattern.FindAllStringSubmatch(path, -1); allMatches != nil { - for _, matches := range allMatches { - // Add the value to the list of covered parameters. - coveredParameters = append(coveredParameters, matches[1]) - pathParameter := g.findAndFormatFieldName(matches[1], inputMessage) - path = strings.Replace(path, matches[1], pathParameter, 1) - - // Add the path parameters to the operation parameters. - var fieldSchema *v3.SchemaOrReference - - var fieldDescription string - field := g.findField(pathParameter, inputMessage) - if field != nil { - fieldSchema = g.schemaOrReferenceForField(field.Desc) - fieldDescription = g.filterCommentString(field.Comments.Leading, true) - } else { - // If field dooes not exist, it is safe to set it to string, as it is ignored downstream - fieldSchema = &v3.SchemaOrReference{ - Oneof: &v3.SchemaOrReference_Schema{ - Schema: &v3.Schema{ - Type: "string", - }, - }, - } - } - - parameters = append(parameters, - &v3.ParameterOrReference{ - Oneof: &v3.ParameterOrReference_Parameter{ - Parameter: &v3.Parameter{ - Name: pathParameter, - In: "path", - Description: fieldDescription, - Required: true, - Schema: fieldSchema, - }, - }, - }) - } - } - - // Find named path parameters like {name=shelves/*} - if matches := g.namedPathPattern.FindStringSubmatch(path); matches != nil { - // Build a list of named path parameters. - namedPathParameters := make([]string, 0) - - // Add the "name=" "name" value to the list of covered parameters. - coveredParameters = append(coveredParameters, matches[1]) - // Convert the path from the starred form to use named path parameters. - starredPath := matches[2] - parts := strings.Split(starredPath, "/") - // The starred path is assumed to be in the form "things/*/otherthings/*". - // We want to convert it to "things/{thingsId}/otherthings/{otherthingsId}". - for i := 0; i < len(parts)-1; i += 2 { - section := parts[i] - namedPathParameter := g.findAndFormatFieldName(section, inputMessage) - namedPathParameter = singular(namedPathParameter) - parts[i+1] = "{" + namedPathParameter + "}" - namedPathParameters = append(namedPathParameters, namedPathParameter) - } - // Rewrite the path to use the path parameters. - newPath := strings.Join(parts, "/") - path = strings.Replace(path, matches[0], newPath, 1) - - // Add the named path parameters to the operation parameters. - for _, namedPathParameter := range namedPathParameters { - if _, ok := sparameters[namedPathParameter]; ok { - continue - } - - parameters = append(parameters, - &v3.ParameterOrReference{ - Oneof: &v3.ParameterOrReference_Parameter{ - Parameter: &v3.Parameter{ - Name: namedPathParameter, - In: "path", - Required: true, - Description: "The " + namedPathParameter + " id.", - Schema: &v3.SchemaOrReference{ - Oneof: &v3.SchemaOrReference_Schema{ - Schema: &v3.Schema{ - Type: "string", - }, - }, - }, - }, - }, - }) - } - } - - // Add any unhandled fields in the request message as query parameters. - if bodyField != "*" { - for _, field := range inputMessage.Fields { - fieldName := string(field.Desc.Name()) - if !contains(coveredParameters, fieldName) && fieldName != bodyField { - fieldParams := g.buildQueryParamsV3(field) - parameters = append(parameters, fieldParams...) - } - } - } - - var responses *v3.Responses - if eopt != nil && eopt != v3.E_Openapiv3Operation.InterfaceOf(v3.E_Openapiv3Operation.Zero()) { - opt := eopt.(*v3.Operation) - if r := opt.Responses; r != nil { - responses = r - - rd := responses.Default - if rd != nil { - if ref := rd.GetReference(); ref != nil && ref.GetXRef() != "" { - xref := strings.TrimPrefix(ref.GetXRef(), ".") - description := "Default" - if strings.Contains(xref, "micro.errors.Error") { - description += " Error" - } - desc, err := protofiles.FindDescriptorByName(protoreflect.FullName(xref)) - if err != nil { - log.Printf("unknown ref type %s err %v", xref, err) - } else { - responses.Default.Oneof = &v3.ResponseOrReference_Response{ - Response: &v3.Response{ - Description: description, - Content: g.responseContentForMessage(&protogen.Message{ - Desc: desc.(protoreflect.MessageDescriptor), - }), - }, - } - } - } - } - for _, rref := range responses.GetResponseOrReference() { - if ref := rref.Value.GetReference(); ref != nil && ref.GetXRef() != "" { - xref := strings.TrimPrefix(ref.GetXRef(), ".") - description := "Default" - if strings.Contains(xref, "micro.errors.Error") { - description += " Error" - } - desc, err := protofiles.FindDescriptorByName(protoreflect.FullName(xref)) - if err != nil { - log.Printf("unknown ref type %s err %v", xref, err) - } else { - responses.Default.Oneof = &v3.ResponseOrReference_Response{ - Response: &v3.Response{ - Description: description, - Content: g.responseContentForMessage(&protogen.Message{ - Desc: desc.(protoreflect.MessageDescriptor), - }), - }, - } - } - } - } - } else { - responses = &v3.Responses{} - } - } else { - responses = &v3.Responses{} - } - - // Create the response. - responses.ResponseOrReference = append(responses.ResponseOrReference, &v3.NamedResponseOrReference{ - Name: "200", - Value: &v3.ResponseOrReference{ - Oneof: &v3.ResponseOrReference_Response{ - Response: &v3.Response{ - Description: "OK", - Content: g.responseContentForMessage(outputMessage), - }, - }, - }, - }) - - // Create the operation. - op := &v3.Operation{ - Tags: []string{tagName}, - Description: description, - OperationId: operationID, - Parameters: parameters, - Responses: responses, - } - - if defaultHost != "" { - hostURL, err := url.Parse(defaultHost) - if err == nil { - hostURL.Scheme = "https" - op.Servers = append(op.Servers, &v3.Server{Url: hostURL.String()}) - } - } - - // If a body field is specified, we need to pass a message as the request body. - if bodyField != "" { - var requestSchema *v3.SchemaOrReference - - if bodyField == "*" { - // Pass the entire request message as the request body. - typeName := g.fullMessageTypeName(inputMessage.Desc) - requestSchema = g.schemaOrReferenceForType(typeName) - } else { - // If body refers to a message field, use that type. - for _, field := range inputMessage.Fields { - if string(field.Desc.Name()) == bodyField { - switch field.Desc.Kind() { - case protoreflect.StringKind: - requestSchema = &v3.SchemaOrReference{ - Oneof: &v3.SchemaOrReference_Schema{ - Schema: &v3.Schema{ - Type: "string", - }, - }, - } - - case protoreflect.MessageKind: - typeName := g.fullMessageTypeName(field.Message.Desc) - requestSchema = g.schemaOrReferenceForType(typeName) - - default: - log.Printf("unsupported field type %+v", field.Desc) - } - break - } - } - } - - ctype := getMediaType(eopt) - - op.RequestBody = &v3.RequestBodyOrReference{ - Oneof: &v3.RequestBodyOrReference_RequestBody{ - RequestBody: &v3.RequestBody{ - Required: true, - Content: &v3.MediaTypes{ - AdditionalProperties: []*v3.NamedMediaType{ - { - Name: ctype, - Value: &v3.MediaType{ - Schema: requestSchema, - }, - }, - }, - }, - }, - }, - } - } - return op, path -} - -// addOperationV3 adds an operation to the specified path/method. -func (g *openapiv3Generator) addOperationV3(d *v3.Document, op *v3.Operation, path string, methodName string) { - var selectedPathItem *v3.NamedPathItem - for _, namedPathItem := range d.Paths.Path { - if namedPathItem.Name == path { - selectedPathItem = namedPathItem - break - } - } - // If we get here, we need to create a path item. - if selectedPathItem == nil { - selectedPathItem = &v3.NamedPathItem{Name: path, Value: &v3.PathItem{}} - d.Paths.Path = append(d.Paths.Path, selectedPathItem) - } - // Set the operation on the specified method. - switch methodName { - case "GET": - selectedPathItem.Value.Get = op - case "POST": - selectedPathItem.Value.Post = op - case "PUT": - selectedPathItem.Value.Put = op - case "DELETE": - selectedPathItem.Value.Delete = op - case "PATCH": - selectedPathItem.Value.Patch = op - } -} - -// schemaReferenceForTypeName returns an OpenAPI JSON Reference to the schema that represents a type. -func (g *openapiv3Generator) schemaReferenceForTypeName(typeName string) string { - if !contains(g.requiredSchemas, typeName) { - g.requiredSchemas = append(g.requiredSchemas, typeName) - } - - if typeName == ".google.protobuf.Value" { - return "#/components/schemas/" + protobufValueName - } - - parts := strings.Split(typeName, ".") - lastPart := parts[len(parts)-1] - return "#/components/schemas/" + g.formatMessageRef(lastPart) -} - -// fullMessageTypeName builds the full type name of a message. -func (g *openapiv3Generator) fullMessageTypeName(message protoreflect.MessageDescriptor) string { - name := g.getMessageName(message) - return "." + string(message.ParentFile().Package()) + "." + name -} - -func (g *openapiv3Generator) responseContentForMessage(outputMessage *protogen.Message) *v3.MediaTypes { - typeName := g.fullMessageTypeName(outputMessage.Desc) - - if typeName == ".google.protobuf.Empty" { - return &v3.MediaTypes{} - } - - if typeName == ".google.api.HttpBody" || typeName == ".micro.codec.Frame" || typeName == ".micro.api.HttpBody" { - return &v3.MediaTypes{ - AdditionalProperties: []*v3.NamedMediaType{ - { - Name: "application/octet-stream", - Value: &v3.MediaType{}, - }, - }, - } - } - - return &v3.MediaTypes{ - AdditionalProperties: []*v3.NamedMediaType{ - { - Name: "application/json", - Value: &v3.MediaType{ - Schema: g.schemaOrReferenceForType(typeName), - }, - }, - }, - } -} - -func (g *openapiv3Generator) schemaOrReferenceForType(typeName string) *v3.SchemaOrReference { - switch typeName { - - case ".google.protobuf.Timestamp": - // Timestamps are serialized as strings - return &v3.SchemaOrReference{ - Oneof: &v3.SchemaOrReference_Schema{ - Schema: &v3.Schema{Type: "string", Format: "RFC3339"}, - }, - } - - case ".google.type.Date": - // Dates are serialized as strings - return &v3.SchemaOrReference{ - Oneof: &v3.SchemaOrReference_Schema{ - Schema: &v3.Schema{Type: "string", Format: "date"}, - }, - } - - case ".google.type.DateTime": - // DateTimes are serialized as strings - return &v3.SchemaOrReference{ - Oneof: &v3.SchemaOrReference_Schema{ - Schema: &v3.Schema{Type: "string", Format: "date-time"}, - }, - } - - case ".google.protobuf.FieldMask": - // Field masks are serialized as strings - return &v3.SchemaOrReference{ - Oneof: &v3.SchemaOrReference_Schema{ - Schema: &v3.Schema{Type: "string", Format: "field-mask"}, - }, - } - - case ".google.protobuf.Struct": - // Struct is equivalent to a JSON object - return &v3.SchemaOrReference{ - Oneof: &v3.SchemaOrReference_Schema{ - Schema: &v3.Schema{Type: "object"}, - }, - } - - case ".google.protobuf.Empty": - // Empty is close to JSON undefined than null, so ignore this field - return nil //&v3.SchemaOrReference{Oneof: &v3.SchemaOrReference_Schema{Schema: &v3.Schema{Type: "null"}}} - - default: - ref := g.schemaReferenceForTypeName(typeName) - return &v3.SchemaOrReference{ - Oneof: &v3.SchemaOrReference_Reference{ - Reference: &v3.Reference{XRef: ref}, - }, - } - } -} - -func (g *openapiv3Generator) schemaOrReferenceForField(field protoreflect.FieldDescriptor) *v3.SchemaOrReference { - if field.IsMap() { - return &v3.SchemaOrReference{ - Oneof: &v3.SchemaOrReference_Schema{ - Schema: &v3.Schema{ - Type: "object", - AdditionalProperties: &v3.AdditionalPropertiesItem{ - Oneof: &v3.AdditionalPropertiesItem_SchemaOrReference{ - SchemaOrReference: g.schemaOrReferenceForField(field.MapValue()), - }, - }, - }, - }, - } - } - - var kindSchema *v3.SchemaOrReference - - kind := field.Kind() - - switch kind { - - case protoreflect.MessageKind: - typeName := g.fullMessageTypeName(field.Message()) - kindSchema = g.schemaOrReferenceForType(typeName) - if kindSchema == nil { - return nil - } - - case protoreflect.StringKind: - kindSchema = &v3.SchemaOrReference{ - Oneof: &v3.SchemaOrReference_Schema{ - Schema: &v3.Schema{Type: "string"}, - }, - } - - case protoreflect.Int32Kind, protoreflect.Sint32Kind, protoreflect.Uint32Kind, - protoreflect.Int64Kind, protoreflect.Sint64Kind, protoreflect.Uint64Kind, - protoreflect.Sfixed32Kind, protoreflect.Fixed32Kind, protoreflect.Sfixed64Kind, - protoreflect.Fixed64Kind: - kindSchema = &v3.SchemaOrReference{ - Oneof: &v3.SchemaOrReference_Schema{ - Schema: &v3.Schema{Type: "integer", Format: kind.String()}, - }, - } - - case protoreflect.EnumKind: - kindSchema = &v3.SchemaOrReference{ - Oneof: &v3.SchemaOrReference_Schema{ - Schema: &v3.Schema{Type: "integer", Format: "enum"}, - }, - } - - case protoreflect.BoolKind: - kindSchema = &v3.SchemaOrReference{ - Oneof: &v3.SchemaOrReference_Schema{ - Schema: &v3.Schema{Type: "boolean"}, - }, - } - - case protoreflect.FloatKind, protoreflect.DoubleKind: - kindSchema = &v3.SchemaOrReference{ - Oneof: &v3.SchemaOrReference_Schema{ - Schema: &v3.Schema{Type: "number", Format: kind.String()}, - }, - } - - case protoreflect.BytesKind: - kindSchema = &v3.SchemaOrReference{ - Oneof: &v3.SchemaOrReference_Schema{ - Schema: &v3.Schema{Type: "string", Format: "bytes"}, - }, - } - - default: - log.Printf("(TODO) Unsupported field type: %+v", g.fullMessageTypeName(field.Message())) - } - - if field.IsList() { - return &v3.SchemaOrReference{ - Oneof: &v3.SchemaOrReference_Schema{ - Schema: &v3.Schema{ - Type: "array", - Items: &v3.ItemsItem{SchemaOrReference: []*v3.SchemaOrReference{kindSchema}}, - }, - }, - } - } - - return kindSchema -} - -// addSchemasToDocumentV3 adds info from one file descriptor. -func (g *openapiv3Generator) addSchemasToDocumentV3(d *v3.Document, messages []*protogen.Message) { - // For each message, generate a definition. - for _, message := range messages { - if message.Messages != nil { - g.addSchemasToDocumentV3(d, message.Messages) - } - - typeName := g.fullMessageTypeName(message.Desc) - - // Only generate this if we need it and haven't already generated it. - if !contains(g.requiredSchemas, typeName) || - contains(g.generatedSchemas, typeName) { - continue - } - - g.generatedSchemas = append(g.generatedSchemas, typeName) - - // google.protobuf.Value is handled like a special value when doing transcoding. - // It's interpreted as a "catch all" JSON value, that can be anything. - if message.Desc != nil && message.Desc.FullName() == "google.protobuf.Value" { - // Add the schema to the components.schema list. - description := protobufValueName + ` is a "catch all" type that can hold any JSON value, except null as this is not allowed in OpenAPI` - - d.Components.Schemas.AdditionalProperties = append(d.Components.Schemas.AdditionalProperties, - &v3.NamedSchemaOrReference{ - Name: protobufValueName, - Value: &v3.SchemaOrReference{ - Oneof: &v3.SchemaOrReference_Schema{ - Schema: &v3.Schema{ - Description: description, - OneOf: []*v3.SchemaOrReference{ - // type is not allow to be null in OpenAPI - { - Oneof: &v3.SchemaOrReference_Schema{ - Schema: &v3.Schema{Type: "string"}, - }, - }, { - Oneof: &v3.SchemaOrReference_Schema{ - Schema: &v3.Schema{Type: "number"}, - }, - }, { - Oneof: &v3.SchemaOrReference_Schema{ - Schema: &v3.Schema{Type: "integer"}, - }, - }, { - Oneof: &v3.SchemaOrReference_Schema{ - Schema: &v3.Schema{Type: "boolean"}, - }, - }, { - Oneof: &v3.SchemaOrReference_Schema{ - Schema: &v3.Schema{Type: "object"}, - }, - }, { - Oneof: &v3.SchemaOrReference_Schema{ - Schema: &v3.Schema{ - Type: "array", - Items: &v3.ItemsItem{ - SchemaOrReference: []*v3.SchemaOrReference{{ - Oneof: &v3.SchemaOrReference_Reference{ - Reference: &v3.Reference{XRef: "#/components/schemas/" + protobufValueName}, - }, - }}, - }, - }, - }, - }, - }, - }, - }, - }, - }, - ) - continue - } - - // Get the message description from the comments. - messageDescription := g.filterCommentString(message.Comments.Leading, true) - - // Build an array holding the fields of the message. - definitionProperties := &v3.Properties{ - AdditionalProperties: make([]*v3.NamedSchemaOrReference, 0), - } - - var required []string - for _, field := range message.Fields { - // Check the field annotations to see if this is a readonly or writeonly field. - inputOnly := false - outputOnly := false - extension := proto.GetExtension(field.Desc.Options(), api.E_FieldBehavior) - if extension != nil { - switch v := extension.(type) { - case []api.FieldBehavior: - for _, vv := range v { - switch vv { - case api.FieldBehavior_OUTPUT_ONLY: - outputOnly = true - case api.FieldBehavior_INPUT_ONLY: - inputOnly = true - case api.FieldBehavior_REQUIRED: - required = append(required, g.formatFieldName(field)) - } - } - default: - log.Printf("unsupported extension type %T", extension) - } - } - - // The field is either described by a reference or a schema. - fieldSchema := g.schemaOrReferenceForField(field.Desc) - if fieldSchema == nil { - continue - } - - if schema, ok := fieldSchema.Oneof.(*v3.SchemaOrReference_Schema); ok { - // Get the field description from the comments. - schema.Schema.Description = g.filterCommentString(field.Comments.Leading, true) - if outputOnly { - schema.Schema.ReadOnly = true - } - if inputOnly { - schema.Schema.WriteOnly = true - } - } - - definitionProperties.AdditionalProperties = append( - definitionProperties.AdditionalProperties, - &v3.NamedSchemaOrReference{ - Name: g.formatFieldName(field), - Value: fieldSchema, - }, - ) - } - // Add the schema to the components.schema list. - d.Components.Schemas.AdditionalProperties = append(d.Components.Schemas.AdditionalProperties, - &v3.NamedSchemaOrReference{ - Name: g.formatMessageName(message), - Value: &v3.SchemaOrReference{ - Oneof: &v3.SchemaOrReference_Schema{ - Schema: &v3.Schema{ - Type: "object", - Description: messageDescription, - Properties: definitionProperties, - Required: required, - }, - }, - }, - }, - ) - } -} - -// contains returns true if an array contains a specified string. -func contains(s []string, e string) bool { - for _, a := range s { - if a == e { - return true - } - } - return false -} - -// appendUniuqe appends a string, to a string slice, if the string is not already in the slice -func appendUniuqe(s []string, e string) []string { - if !contains(s, e) { - return append(s, e) - } - return s -} - -// singular produces the singular form of a collection name. -func singular(plural string) string { - if strings.HasSuffix(plural, "ves") { - return strings.TrimSuffix(plural, "ves") + "f" - } - if strings.HasSuffix(plural, "ies") { - return strings.TrimSuffix(plural, "ies") + "y" - } - if strings.HasSuffix(plural, "s") { - return strings.TrimSuffix(plural, "s") - } - return plural -} diff --git a/openapiv3_util.go b/openapiv3_util.go deleted file mode 100644 index 47e3ef6..0000000 --- a/openapiv3_util.go +++ /dev/null @@ -1,39 +0,0 @@ -package main - -import v3 "go.unistack.org/micro-proto/v4/openapiv3" - -func getMediaType(eopt interface{}) string { - ctype := "application/json" - - if eopt == nil { - return ctype - } - - if eopt == v3.E_Openapiv3Operation.InterfaceOf(v3.E_Openapiv3Operation.Zero()) { - return ctype - } - - opt, ok := eopt.(*v3.Operation) - if !ok || opt.RequestBody == nil { - return ctype - } - - if opt.GetRequestBody() == nil { - return ctype - } - - if opt.GetRequestBody().GetRequestBody() == nil { - return ctype - } - - c := opt.GetRequestBody().GetRequestBody().GetContent() - if c == nil { - return ctype - } - - for _, prop := range c.GetAdditionalProperties() { - ctype = prop.Name - } - - return ctype -} diff --git a/rpc.go b/rpc.go deleted file mode 100644 index 38c2942..0000000 --- a/rpc.go +++ /dev/null @@ -1,55 +0,0 @@ -package main - -import ( - "google.golang.org/protobuf/compiler/protogen" -) - -func (g *Generator) rpcGenerate(component string, plugin *protogen.Plugin, genClient bool, genServer bool) error { - for _, file := range plugin.Files { - if !file.Generate { - continue - } - if len(file.Services) == 0 { - continue - } - - gname := file.GeneratedFilenamePrefix + "_micro_" + component + ".pb.go" - path := file.GoImportPath - if g.standalone { - path = "." - } - gfile := plugin.NewGeneratedFile(gname, path) - - gfile.P("// Code generated by protoc-gen-go-micro. DO NOT EDIT.") - gfile.P("// protoc-gen-go-micro version: " + versionComment) - gfile.P("// source: ", file.Proto.GetName()) - gfile.P() - gfile.P("package ", file.GoPackageName) - gfile.P() - - gfile.Import(contextPackage) - - if genClient { - gfile.Import(microClientPackage) - } - if genServer { - gfile.Import(microServerPackage) - } - for _, service := range file.Services { - if genClient { - g.generateServiceClient(gfile, file, service) - g.generateServiceClientMethods(gfile, service, component) - } - if genServer { - g.generateServiceServer(gfile, file, service) - g.generateServiceServerMethods(gfile, service) - g.generateServiceRegister(gfile, file, service, component) - } - if component == "grpc" && g.reflection { - g.generateServiceDesc(gfile, file, service) - } - } - } - - return nil -} diff --git a/templates/e3suU2VydmljZS5OYW1lIHwgdHJpbVN1ZmZpeCAiU2VydmljZSIgfCBsb3dlcn19X21pY3JvX2NoaS5wYi5nby50bXBs b/templates/e3suU2VydmljZS5OYW1lIHwgdHJpbVN1ZmZpeCAiU2VydmljZSIgfCBsb3dlcn19X21pY3JvX2NoaS5wYi5nby50bXBs new file mode 100644 index 0000000..baae940 --- /dev/null +++ b/templates/e3suU2VydmljZS5OYW1lIHwgdHJpbVN1ZmZpeCAiU2VydmljZSIgfCBsb3dlcn19X21pY3JvX2NoaS5wYi5nby50bXBs @@ -0,0 +1,51 @@ +// Code generated by protoc-gen-micro +// source: {{.File.Name}} +package {{goPkgLastElement .File | splitArray ";" | last | replace "." "_"}} + +import ( + "context" + "fmt" + "net/http" + "reflect" + "strings" + + "github.com/go-chi/chi/v4" + middleware "github.com/go-chi/chi/v4/middleware" + micro_api "github.com/unistack-org/micro/v3/api" +) + +type routeKey struct{} + +func RouteName(ctx context.Context) (string, bool) { + value, ok := ctx.Value(routeKey{}).(string) + return value, ok +} + +func {{.Service.Name | trimSuffix "Service"}}ServiceRegister(r *chi.Mux, h interface{}, eps []*micro_api.Endpoint) error { + v := reflect.ValueOf(h) + + if v.NumMethod() < 1 { + return fmt.Errorf("handler has no methods: %T", h) + } + + for _, ep := range eps { + idx := strings.Index(ep.Name, ".") + if idx < 1 || len(ep.Name) <= idx { + return fmt.Errorf("invalid api.Endpoint name: %s", ep.Name) + } + name := ep.Name[idx+1:] + m := v.MethodByName(name) + if !m.IsValid() || m.IsZero() { + return fmt.Errorf("invalid handler, method %s not found", name) + } + + rh, ok := m.Interface().(func(http.ResponseWriter, *http.Request)) + if !ok { + return fmt.Errorf("invalid handler: %#+v", m.Interface()) + } + for _, method := range ep.Method { + r.With(middleware.WithValue(routeKey{}, ep.Name)).MethodFunc(method, ep.Path[0], rh) + } + } + return nil +} diff --git a/templates/e3suU2VydmljZS5OYW1lIHwgdHJpbVN1ZmZpeCAiU2VydmljZSIgfCBsb3dlcn19X21pY3JvX2dvcmlsbGEucGIuZ28udG1wbA== b/templates/e3suU2VydmljZS5OYW1lIHwgdHJpbVN1ZmZpeCAiU2VydmljZSIgfCBsb3dlcn19X21pY3JvX2dvcmlsbGEucGIuZ28udG1wbA== new file mode 100644 index 0000000..f03ca4a --- /dev/null +++ b/templates/e3suU2VydmljZS5OYW1lIHwgdHJpbVN1ZmZpeCAiU2VydmljZSIgfCBsb3dlcn19X21pY3JvX2dvcmlsbGEucGIuZ28udG1wbA== @@ -0,0 +1,40 @@ +// Code generated by protoc-gen-micro +// source: {{.File.Name}} +package {{goPkgLastElement .File | splitArray ";" | last | replace "." "_"}} + +import ( + "fmt" + "net/http" + "reflect" + "strings" + + "github.com/gorilla/mux" + micro_api "github.com/unistack-org/micro/v3/api" +) + +func {{.Service.Name | trimSuffix "Service"}}ServiceRegister(r *mux.Router, h interface{}, eps []*micro_api.Endpoint) error { + v := reflect.ValueOf(h) + + if v.NumMethod() < 1 { + return fmt.Errorf("handler has no methods: %T", h) + } + + for _, ep := range eps { + idx := strings.Index(ep.Name, ".") + if idx < 1 || len(ep.Name) <= idx { + return fmt.Errorf("invalid api.Endpoint name: %s", ep.Name) + } + name := ep.Name[idx+1:] + m := v.MethodByName(name) + if !m.IsValid() || m.IsZero() { + return fmt.Errorf("invalid handler, method %s not found", name) + } + + rh, ok := m.Interface().(func(http.ResponseWriter, *http.Request)) + if !ok { + return fmt.Errorf("invalid handler: %#+v", m.Interface()) + } + r.HandleFunc(ep.Path[0], rh).Methods(ep.Method...).Name(ep.Name) + } + return nil +} diff --git a/templates/e3t0cmltU3VmZml4ICIucHJvdG8iIC5GaWxlLk5hbWV9fV9taWNyb19ncnBjLnBiLmdvLnRtcGw= b/templates/e3t0cmltU3VmZml4ICIucHJvdG8iIC5GaWxlLk5hbWV9fV9taWNyb19ncnBjLnBiLmdvLnRtcGw= new file mode 100644 index 0000000..eb9a69b --- /dev/null +++ b/templates/e3t0cmltU3VmZml4ICIucHJvdG8iIC5GaWxlLk5hbWV9fV9taWNyb19ncnBjLnBiLmdvLnRtcGw= @@ -0,0 +1,215 @@ +// Code generated by protoc-gen-micro +// source: {{.File.Name}} +package {{goPkgLastElement .File | splitArray ";" | last | replace "." "_"}} + +import ( + "context" + + micro_api "github.com/unistack-org/micro/v3/api" + micro_client "github.com/unistack-org/micro/v3/client" + micro_server "github.com/unistack-org/micro/v3/server" +) + +var ( + _ micro_server.Option + _ micro_client.Option +) + +{{- $File := .File }} +{{- $ServiceName := .Service.Name | trimSuffix "Service" }} + +type {{$ServiceName | lowerFirst}}Service struct { + c micro_client.Client + name string +} + +// Micro client stuff + +// New{{$ServiceName}}Service create new service client +func New{{$ServiceName}}Service(name string, c micro_client.Client) {{$ServiceName}}Service { + return &{{$ServiceName | lowerFirst}}Service{c: c, name: name} +} + +{{range .Service.Method}} +{{- $reqMethod := .InputType | splitArray "." | last}} +{{- $rspMethod := .OutputType | splitArray "." | last}} +{{- if and (not .ClientStreaming) (.ServerStreaming) -}} +func (c *{{$ServiceName | lowerFirst}}Service) {{.Name}}(ctx context.Context, req *{{$reqMethod}}, opts ...micro_client.CallOption) ({{$ServiceName}}_{{.Name}}Service, error) { + {{- else if .ClientStreaming -}} +func (c *{{$ServiceName | lowerFirst}}Service) {{.Name}}(ctx context.Context, opts ...micro_client.CallOption) ({{$ServiceName}}_{{.Name}}Service, error) { + {{- else -}} +func (c *{{$ServiceName | lowerFirst}}Service) {{.Name}}(ctx context.Context, req *{{$reqMethod}}, opts ...micro_client.CallOption) (*{{$rspMethod}}, error) { + {{- end -}} + {{- if or (.ServerStreaming) (.ClientStreaming)}} + stream, err := c.c.Stream(ctx, c.c.NewRequest(c.name, "{{$ServiceName}}.{{.Name}}", &{{$reqMethod}}{}), opts...) + if err != nil { + return nil, err + } + {{- if not .ClientStreaming }} + if err := stream.Send(req); err != nil { + return nil, err + } + {{- end}} + return &{{$ServiceName | lowerFirst}}Service{{.Name}}{stream}, nil + {{- else}} + rsp := &{{$rspMethod}}{} + err := c.c.Call(ctx, c.c.NewRequest(c.name, "{{$ServiceName}}.{{.Name}}", req), rsp, opts...) + if err != nil { + return nil, err + } + return rsp, nil + {{- end}} +} + +{{if or (.ServerStreaming) (.ClientStreaming)}} +type {{$ServiceName | lowerFirst}}Service{{.Name}} struct { + stream micro_client.Stream +} +{{if and (.ClientStreaming) (not .ServerStreaming)}} +func (x *{{$ServiceName | lowerFirst}}Service{{.Name}}) RecvAndClose() (*{{$rspMethod}}, error) { + m := &{{$rspMethod}}{} + err := x.RecvMsg(m) + if err == nil { + err = x.Close() + } + + if err != nil { + return nil, err + } + + return m, nil +} +{{- end}} + +func (x *{{$ServiceName | lowerFirst}}Service{{.Name}}) Close() error { + return x.stream.Close() +} + +func (x *{{$ServiceName | lowerFirst}}Service{{.Name}}) Context() context.Context { + return x.stream.Context() +} + +func (x *{{$ServiceName | lowerFirst}}Service{{.Name}}) SendMsg(m interface{}) error { + return x.stream.Send(m) +} + +func (x *{{$ServiceName | lowerFirst}}Service{{.Name}}) RecvMsg(m interface{}) error { + return x.stream.Recv(m) +} + +{{ if .ClientStreaming -}} +func (x *{{$ServiceName | lowerFirst}}Service{{.Name}}) Send(m *{{$reqMethod}}) error { + return x.stream.Send(m) +} +{{end}} + +{{ if .ServerStreaming -}} +func (x *{{$ServiceName | lowerFirst}}Service{{.Name}}) Recv() (*{{$rspMethod}}, error) { + m := &{{$rspMethod}}{} + if err := x.stream.Recv(m); err != nil { + return nil, err + } + return m, nil +} +{{ end }} + +{{- end}} +{{- end}} + +// Micro server stuff + +type {{$ServiceName | lowerFirst}}Handler struct { + {{$ServiceName}}Handler +} +{{range .Service.Method }} +{{- $reqMethod := .InputType | splitArray "." | last}} +{{- $rspMethod := .OutputType | splitArray "." | last}} +{{- if or (.ServerStreaming) (.ClientStreaming)}} +func (h *{{$ServiceName | lowerFirst}}Handler) {{.Name}}(ctx context.Context, stream micro_server.Stream) error { +{{- if not .ClientStreaming}} + m := &{{$reqMethod}}{} + if err := stream.Recv(m); err != nil { + return err + } + return h.{{$ServiceName}}Handler.{{.Name}}(ctx, m, &{{$ServiceName | lowerFirst}}{{.Name}}Stream{stream}) +{{- else}} + return h.{{$ServiceName}}Handler.{{.Name}}(ctx, &{{$ServiceName | lowerFirst}}{{.Name}}Stream{stream}) +{{- end}} +} +{{- else}} +func (h *{{$ServiceName | lowerFirst}}Handler) {{.Name}}(ctx context.Context, req *{{$reqMethod}}, rsp *{{$rspMethod}}) error { + return h.{{$ServiceName}}Handler.{{.Name}}(ctx, req, rsp) +} +{{- end}} +{{if or (.ServerStreaming) (.ClientStreaming)}} +type {{$ServiceName | lowerFirst}}{{.Name}}Stream struct { + stream micro_server.Stream +} +{{if and (.ClientStreaming) (not .ServerStreaming)}} +func (x *{{$ServiceName | lowerFirst}}{{.Name}}Stream) SendAndClose(m *{{$rspMethod}}) error { + err := x.SendMsg(m) + if err == nil { + err = x.stream.Close() + } + return err +} +{{- end}} + +func (x *{{$ServiceName | lowerFirst}}{{.Name}}Stream) Close() error { + return x.stream.Close() +} + +func (x *{{$ServiceName | lowerFirst}}{{.Name}}Stream) Context() context.Context { + return x.stream.Context() +} + +func (x *{{$ServiceName | lowerFirst}}{{.Name}}Stream) SendMsg(m interface{}) error { + return x.stream.Send(m) +} + +func (x *{{$ServiceName | lowerFirst}}{{.Name}}Stream) RecvMsg(m interface{}) error { + return x.stream.Recv(m) +} + +{{- if .ServerStreaming}} +func (x *{{$ServiceName | lowerFirst}}{{.Name}}Stream) Send(m *{{$rspMethod}}) error { + return x.stream.Send(m) +} +{{end}} + +{{if .ClientStreaming}} +func (x *{{$ServiceName | lowerFirst}}{{.Name}}Stream) Recv() (*{{$reqMethod}}, error) { + m := &{{$reqMethod}}{} + if err := x.stream.Recv(m); err != nil { + return nil, err + } + return m, nil +} +{{end}} + +{{end}} +{{end}} + +// Register{{$ServiceName}}Handler registers server handler +func Register{{$ServiceName}}Handler(s micro_server.Server, sh {{$ServiceName}}Handler, opts ...micro_server.HandlerOption) error { + type {{$ServiceName | lowerFirst}} interface { + {{- range .Service.Method}} +{{- $reqMethod := .InputType | splitArray "." | last}} +{{- $rspMethod := .OutputType | splitArray "." | last}} +{{- if or (.ServerStreaming) (.ClientStreaming)}} + {{.Name}}(context.Context, micro_server.Stream) error +{{- else}} + {{.Name}}(context.Context, *{{$reqMethod}}, *{{$rspMethod}}) error + {{- end}} + {{- end}} + } + type {{$ServiceName}} struct { + {{$ServiceName | lowerFirst}} + } + h := &{{$ServiceName | lowerFirst}}Handler{sh} + for _, endpoint := range New{{$ServiceName}}Endpoints() { + opts = append(opts, micro_api.WithEndpoint(endpoint)) + } + return s.Handle(s.NewHandler(&{{$ServiceName}}{h}, opts...)) +} + diff --git a/templates/e3t0cmltU3VmZml4ICIucHJvdG8iIC5GaWxlLk5hbWV9fV9taWNyb19odHRwLnBiLmdvLnRtcGw= b/templates/e3t0cmltU3VmZml4ICIucHJvdG8iIC5GaWxlLk5hbWV9fV9taWNyb19odHRwLnBiLmdvLnRtcGw= new file mode 100644 index 0000000..543aa18 --- /dev/null +++ b/templates/e3t0cmltU3VmZml4ICIucHJvdG8iIC5GaWxlLk5hbWV9fV9taWNyb19odHRwLnBiLmdvLnRtcGw= @@ -0,0 +1,267 @@ +// Code generated by protoc-gen-micro +// source: {{.File.Name}} +package {{goPkgLastElement .File | splitArray ";" | last | replace "." "_"}} + +{{- $File := .File }} +{{- $ServiceName := .Service.Name | trimSuffix "Service" }} + +{{- $errmsg := list }} +{{range .Service.Method}} +{{- if not (contains (json (openapiOption .)) "null") }} +{{- if (openapiOption .).Responses }} +{{ range $k, $v := (openapiOption .).Responses }} +{{- $msgtype := (getMessageType $File $v.Schema.JsonSchema.Ref) }} +{{- $errmsg = append $errmsg $msgtype.Name }} +{{- end }} +{{- end }} +{{- end }} +{{- end }} + +import ( + "context" +{{- if ne (lenght $errmsg) 0 }} + "fmt" +{{- end }} +// "net/http" + + micro_client "github.com/unistack-org/micro/v3/client" + micro_server "github.com/unistack-org/micro/v3/server" + micro_api "github.com/unistack-org/micro/v3/api" + micro_client_http "github.com/unistack-org/micro-client-http/v3" +) + +var ( + _ micro_server.Option + _ micro_client.Option +) + +type {{$ServiceName | lowerFirst}}Service struct { + c micro_client.Client + name string +} + +// Micro client stuff + +// New{{$ServiceName}}Service create new service client +func New{{$ServiceName}}Service(name string, c micro_client.Client) {{$ServiceName}}Service { + return &{{$ServiceName | lowerFirst}}Service{c: c, name: name} +} + +{{range .Service.Method}} +{{- $reqMethod := .InputType | splitArray "." | last}} +{{- $rspMethod := .OutputType | splitArray "." | last}} +{{ if and (not .ClientStreaming) (.ServerStreaming) }} +func (c *{{$ServiceName | lowerFirst}}Service) {{.Name}}(ctx context.Context, req *{{$reqMethod}}, opts ...micro_client.CallOption) ({{$ServiceName}}_{{.Name}}Service, error) { + {{ else if .ClientStreaming }} +func (c *{{$ServiceName | lowerFirst}}Service) {{.Name}}(ctx context.Context, opts ...micro_client.CallOption) ({{$ServiceName}}_{{.Name}}Service, error) { + {{ else }} +func (c *{{$ServiceName | lowerFirst}}Service) {{.Name}}(ctx context.Context, req *{{$reqMethod}}, opts ...micro_client.CallOption) (*{{$rspMethod}}, error) { + {{- end }} + {{- if not (contains (json (openapiOption .)) "null") }} + {{- if (openapiOption .).Responses }} + errmap := make(map[string]interface{}, {{ len (openapiOption .).Responses}}) + {{- range $k, $v := (openapiOption .).Responses }} + errmap["{{$k}}"] = &{{- (getMessageType $File $v.Schema.JsonSchema.Ref).Name }}{} + {{- end }} + {{- end }} + {{ end }} + nopts := append(opts, + micro_client_http.Method("{{httpVerb .}}"), + micro_client_http.Path("{{httpPath .}}"), + {{- if not (contains (httpBody .) "GET") }} + micro_client_http.Body("{{httpBody .}}"), + {{- end }} + {{- if not (contains (json (openapiOption .)) "null") }} + {{- if (openapiOption .).Responses }} + micro_client_http.ErrorMap(errmap), + {{- end }} + {{- end }} + ) + {{- if or (.ServerStreaming) (.ClientStreaming)}} + stream, err := c.c.Stream(ctx, c.c.NewRequest(c.name, "{{$ServiceName}}.{{.Name}}", &{{$reqMethod}}{}), nopts...) + if err != nil { + return nil, err + } + {{- if not .ClientStreaming }} + if err := stream.Send(req); err != nil { + return nil, err + } + {{- end}} + return &{{$ServiceName | lowerFirst}}Service{{.Name}}{stream}, nil + {{- else}} + rsp := &{{$rspMethod}}{} + err := c.c.Call(ctx, c.c.NewRequest(c.name, "{{$ServiceName}}.{{.Name}}", req), rsp, nopts...) + if err != nil { + return nil, err + } + return rsp, nil + {{- end}} +} + +{{if or (.ServerStreaming) (.ClientStreaming)}} +type {{$ServiceName | lowerFirst}}Service{{.Name}} struct { + stream micro_client.Stream +} +{{if and (.ClientStreaming) (not .ServerStreaming)}} +func (x *{{$ServiceName | lowerFirst}}Service{{.Name}}) RecvAndClose() (*{{$rspMethod}}, error) { + m := &{{$rspMethod}}{} + err := x.RecvMsg(m) + if err == nil { + err = x.Close() + } + + if err != nil { + return nil, err + } + + return m, nil +} +{{- end}} + +func (x *{{$ServiceName | lowerFirst}}Service{{.Name}}) Close() error { + return x.stream.Close() +} + +func (x *{{$ServiceName | lowerFirst}}Service{{.Name}}) Context() context.Context { + return x.stream.Context() +} + +func (x *{{$ServiceName | lowerFirst}}Service{{.Name}}) SendMsg(m interface{}) error { + return x.stream.Send(m) +} + +func (x *{{$ServiceName | lowerFirst}}Service{{.Name}}) RecvMsg(m interface{}) error { + return x.stream.Recv(m) +} + +{{ if .ClientStreaming -}} +func (x *{{$ServiceName | lowerFirst}}Service{{.Name}}) Send(m *{{$reqMethod}}) error { + return x.stream.Send(m) +} +{{- end}} + +{{ if .ServerStreaming -}} +func (x *{{$ServiceName | lowerFirst}}Service{{.Name}}) Recv() (*{{$rspMethod}}, error) { + m := &{{$rspMethod}}{} + if err := x.stream.Recv(m); err != nil { + return nil, err + } + return m, nil +} +{{- end }} + +{{- end}} +{{end}} + +// Micro server stuff + +type {{$ServiceName | lowerFirst}}Handler struct { + {{$ServiceName}}Handler +} +{{range .Service.Method }} +{{- $reqMethod := .InputType | splitArray "." | last}} +{{- $rspMethod := .OutputType | splitArray "." | last}} +{{- if or (.ServerStreaming) (.ClientStreaming)}} +func (h *{{$ServiceName | lowerFirst}}Handler) {{.Name}}(ctx context.Context, stream micro_server.Stream) error { +{{- if not .ClientStreaming}} + m := &{{$reqMethod}}{} + if err := stream.Recv(m); err != nil { + return err + } + return h.{{$ServiceName}}Handler.{{.Name}}(ctx, m, &{{$ServiceName | lowerFirst}}{{.Name}}Stream{stream}) +{{- else}} + return h.{{$ServiceName}}Handler.{{.Name}}(ctx, &{{$ServiceName | lowerFirst}}{{.Name}}Stream{stream}) +{{- end}} +} +{{- else}} +func (h *{{$ServiceName | lowerFirst}}Handler) {{.Name}}(ctx context.Context, req *{{$reqMethod}}, rsp *{{$rspMethod}}) error { + return h.{{$ServiceName}}Handler.{{.Name}}(ctx, req, rsp) +} +{{- end}} + +/* +func (h *{{$ServiceName | lowerFirst}}Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) { + fmt.Printf("new request: %#+v\n", r) + // HANDLE ALL STUFF +} +*/ + +{{if or (.ServerStreaming) (.ClientStreaming)}} +type {{$ServiceName | lowerFirst}}{{.Name}}Stream struct { + stream micro_server.Stream +} +{{if and (.ClientStreaming) (not .ServerStreaming)}} +func (x *{{$ServiceName | lowerFirst}}{{.Name}}Stream) SendAndClose(m *{{$rspMethod}}) error { + err := x.SendMsg(m) + if err == nil { + err = x.stream.Close() + } + return err +} +{{- end}} + +func (x *{{$ServiceName | lowerFirst}}{{.Name}}Stream) Close() error { + return x.stream.Close() +} + +func (x *{{$ServiceName | lowerFirst}}{{.Name}}Stream) Context() context.Context { + return x.stream.Context() +} + +func (x *{{$ServiceName | lowerFirst}}{{.Name}}Stream) SendMsg(m interface{}) error { + return x.stream.Send(m) +} + +func (x *{{$ServiceName | lowerFirst}}{{.Name}}Stream) RecvMsg(m interface{}) error { + return x.stream.Recv(m) +} +{{if .ServerStreaming}} +func (x *{{$ServiceName | lowerFirst}}{{.Name}}Stream) Send(m *{{$rspMethod}}) error { + return x.stream.Send(m) +} +{{end}} + +{{if .ClientStreaming}} +func (x *{{$ServiceName | lowerFirst}}{{.Name}}Stream) Recv() (*{{$reqMethod}}, error) { + m := &{{$reqMethod}}{} + if err := x.stream.Recv(m); err != nil { + return nil, err + } + return m, nil +} +{{end}} + +{{end}} +{{end}} + +{{range $k, $v := ($errmsg | uniq) }} +// Error method to satisfy error interface +func (e *{{- $v }}) Error() string { + return fmt.Sprintf("%#v", e) +} +{{- end }} + +// Register{{$ServiceName}}Handler registers server handler +func Register{{$ServiceName}}Handler(s micro_server.Server, sh {{$ServiceName}}Handler, opts ...micro_server.HandlerOption) error { + type {{$ServiceName | lowerFirst}} interface { + {{- range .Service.Method}} +{{- $reqMethod := .InputType | splitArray "." | last}} +{{- $rspMethod := .OutputType | splitArray "." | last}} +{{- if or (.ServerStreaming) (.ClientStreaming)}} + {{.Name}}(context.Context, micro_server.Stream) error +{{- else}} + {{.Name}}(context.Context, *{{$reqMethod}}, *{{$rspMethod}}) error + {{- end}} + {{- end}} +// ServeHTTP(http.ResponseWriter, *http.Request) + } + type {{$ServiceName}} struct { + {{$ServiceName | lowerFirst}} + } + h := &{{$ServiceName | lowerFirst}}Handler{sh} + for _, endpoint := range New{{$ServiceName}}Endpoints() { + opts = append(opts, micro_api.WithEndpoint(endpoint)) + } + return s.Handle(s.NewHandler(&{{$ServiceName}}{h}, opts...)) +} + diff --git a/templates/e3t0cmltU3VmZml4ICIucHJvdG8iIC5GaWxlLk5hbWV9fV9taWNyby5wYi5nby50bXBs b/templates/e3t0cmltU3VmZml4ICIucHJvdG8iIC5GaWxlLk5hbWV9fV9taWNyby5wYi5nby50bXBs new file mode 100644 index 0000000..cc3aedd --- /dev/null +++ b/templates/e3t0cmltU3VmZml4ICIucHJvdG8iIC5GaWxlLk5hbWV9fV9taWNyby5wYi5nby50bXBs @@ -0,0 +1,142 @@ +// Code generated by protoc-gen-micro +// source: {{.File.Name}} +package {{goPkgLastElement .File | splitArray ";" | last | replace "." "_"}} + +import ( + "context" + + micro_api "github.com/unistack-org/micro/v3/api" + micro_client "github.com/unistack-org/micro/v3/client" +) + +{{- $ServiceName := .Service.Name | trimSuffix "Service" }} +{{- $epnum := 0 }} +{{- range .Service.Method}} +{{- if not (contains (json (httpOption .)) "null") }} +{{- if ne (httpVerb .) "" }} +{{- $epnum = add $epnum 1 }} +{{- range httpPathsAdditionalBindings . }} +{{- $epnum = add $epnum 1 }} +{{- end }} +{{- end }} +{{- end }} +{{- end }} + +// New{{$ServiceName}}Endpoints provides api endpoints metdata for {{$ServiceName}} service +func New{{$ServiceName}}Endpoints() []*micro_api.Endpoint { + endpoints := make([]*micro_api.Endpoint, 0, {{ $epnum }}) + {{- if ne $epnum 0 }} + var endpoint *micro_api.Endpoint + {{- end }} + {{- range .Service.Method}} + {{- if not (contains (json (httpOption .)) "null") }} + {{- $httpOption := (httpOption .) }} + {{- if ne $httpOption.Method "" }} + endpoint = µ_api.Endpoint{ + Name: "{{$ServiceName}}.{{.Name}}", + Path: []string{"{{$httpOption.Path}}"}, + Method: []string{"{{$httpOption.Method}}"}, + Body: "{{$httpOption.Body}}", + {{- if or (.ClientStreaming) (.ServerStreaming)}} + Stream: true, + {{- end}} + Handler: "rpc", + } + endpoints = append(endpoints, endpoint) + {{- range $index, $element := $httpOption.Additional }} + endpoint = µ_api.Endpoint{ + Name: "{{$ServiceName}}.{{.Name}}", + Path: []string{"{{$element.Path}}"}, + Method: []string{"{{$element.Method}}"}, + Body: "{{$element.Body}}", + {{- if or (.ClientStreaming) (.ServerStreaming)}} + Stream: true, + {{- end}} + Handler: "rpc", + } + endpoints = append(endpoints, endpoint) + {{- end}} + {{- end}} + {{- end}} + {{- end}} + return endpoints +} + +// {{$ServiceName}}Service interface +type {{$ServiceName}}Service interface { + {{- range .Service.Method}} + {{- $reqMethod := .InputType | splitArray "." | last }} + {{- $rspMethod := .OutputType | splitArray "." | last }} + {{- if or (.ServerStreaming) (.ClientStreaming)}} + {{- if and (.ServerStreaming) (not .ClientStreaming)}} + {{.Name}}(context.Context, *{{$reqMethod}}, ...micro_client.CallOption) ({{$ServiceName}}_{{.Name}}Service, error) + {{- else}} + {{.Name}}(context.Context, ...micro_client.CallOption) ({{$ServiceName}}_{{.Name}}Service, error) + {{- end}} + {{- else}} + {{.Name}}(context.Context, *{{$reqMethod}}, ...micro_client.CallOption) (*{{$rspMethod}}, error) + {{- end}} + {{- end}} +} + +{{range .Service.Method}} +{{- $reqMethod := .InputType | splitArray "." | last}} +{{- $rspMethod := .OutputType | splitArray "." | last}} +{{if or (.ServerStreaming) (.ClientStreaming)}} +type {{$ServiceName}}_{{.Name}}Service interface { + Context() context.Context + SendMsg(interface{}) error + RecvMsg(interface{}) error + {{- if and (.ClientStreaming) (not .ServerStreaming)}} + RecvAndClose() (*{{$rspMethod}}, error) + {{- end}} + Close() error + {{- if .ClientStreaming}} + Send(*{{$reqMethod}}) error + {{- end}} + {{- if .ServerStreaming}} + Recv() (*{{$rspMethod}}, error) + {{- end}} +} +{{- end}} +{{- end}} +// Micro server stuff + +// {{$ServiceName}}Handler server handler +type {{$ServiceName}}Handler interface { + {{- range .Service.Method}} +{{- $reqMethod := .InputType | splitArray "." | last}} +{{- $rspMethod := .OutputType | splitArray "." | last}} +{{- if or (.ServerStreaming) (.ClientStreaming)}} + {{- if not .ClientStreaming}} + {{.Name}}(context.Context, *{{$reqMethod}}, {{$ServiceName}}_{{.Name}}Stream) error + {{- else}} + {{.Name}}(context.Context, {{$ServiceName}}_{{.Name}}Stream) error + {{- end}} +{{- else}} + {{.Name}}(context.Context, *{{$reqMethod}}, *{{$rspMethod}}) error +{{- end}} +{{- end}} +} + +{{- range .Service.Method}} +{{- $reqMethod := .InputType | splitArray "." | last}} +{{- $rspMethod := .OutputType | splitArray "." | last}} +{{if or (.ServerStreaming) (.ClientStreaming)}} +type {{$ServiceName}}_{{.Name}}Stream interface { + Context() context.Context + SendMsg(interface{}) error + RecvMsg(interface{}) error + {{- if and (.ClientStreaming) (not .ServerStreaming)}} + SendAndClose(*{{$rspMethod}}) error + {{- end}} + Close() error + {{- if .ServerStreaming}} + Send(*{{$rspMethod}}) error + {{- end}} + {{- if .ClientStreaming}} + Recv() (*{{$reqMethod}}, error) + {{- end}} +} +{{- end}} +{{- end}} diff --git a/util.go b/util.go deleted file mode 100644 index b7e11aa..0000000 --- a/util.go +++ /dev/null @@ -1,1034 +0,0 @@ -package main - -import ( - "fmt" - "log" - "net/http" - "strconv" - "strings" - "time" - - api_options "go.unistack.org/micro-proto/v4/api" - v2 "go.unistack.org/micro-proto/v4/openapiv2" - v3 "go.unistack.org/micro-proto/v4/openapiv3" - "google.golang.org/protobuf/compiler/protogen" - "google.golang.org/protobuf/proto" -) - -var httpMethodMap = map[string]string{ - http.MethodGet: "MethodGet", - http.MethodHead: "MethodHead", - http.MethodPost: "MethodPost", - http.MethodPut: "MethodPut", - http.MethodPatch: "MethodPatch", - http.MethodDelete: "MethodDelete", - http.MethodConnect: "MethodConnect", - http.MethodOptions: "MethodOptions", - http.MethodTrace: "MethodTrace", -} - -func unexport(s string) string { - return strings.ToLower(s[:1]) + s[1:] -} - -func (g *Generator) generateServiceClient(gfile *protogen.GeneratedFile, file *protogen.File, service *protogen.Service) { - serviceName := getServiceName(service) - // if rule, ok := getMicroApiService(service); ok { - // gfile.P("// client wrappers ", strings.Join(rule.ClientWrappers, ", ")) - // } - gfile.P("type ", unexport(serviceName), "Client struct {") - gfile.P("c ", microClientPackage.Ident("Client")) - gfile.P("name string") - gfile.P("}") - - if g.standalone { - gfile.P("func New", serviceName, "Client(name string, c ", microClientPackage.Ident("Client"), ") ", file.GoImportPath.Ident(serviceName), "Client {") - } else { - gfile.P("func New", serviceName, "Client(name string, c ", microClientPackage.Ident("Client"), ") ", serviceName, "Client {") - } - gfile.P("return &", unexport(serviceName), "Client{c: c, name: name}") - gfile.P("}") - gfile.P() -} - -func (g *Generator) generateServiceClientMethods(gfile *protogen.GeneratedFile, service *protogen.Service, component string) { - serviceName := getServiceName(service) - for _, method := range service.Methods { - methodName := fmt.Sprintf("%s.%s", serviceName, method.GoName) - if component == "drpc" { - methodName = fmt.Sprintf("%s.%s", method.Parent.Desc.FullName(), method.Desc.Name()) - } - g.generateClientFuncSignature(gfile, serviceName, method) - - if component == "http" && method.Desc.Options() != nil { - if proto.HasExtension(method.Desc.Options(), v2.E_Openapiv2Operation) { - opts := proto.GetExtension(method.Desc.Options(), v2.E_Openapiv2Operation) - if opts != nil { - r := opts.(*v2.Operation) - if r.Responses == nil { - goto labelMethod - } - gfile.P("errmap := make(map[string]interface{}, ", len(r.Responses.ResponseCode), ")") - for _, rsp := range r.Responses.ResponseCode { - if schema := rsp.Value.GetJsonReference(); schema != nil { - xref := schema.XRef - if strings.HasPrefix(xref, "."+string(service.Desc.ParentFile().Package())+".") { - xref = strings.TrimPrefix(xref, "."+string(service.Desc.ParentFile().Package())+".") - } - if xref[0] == '.' { - xref = xref[1:] - } - switch xref { - case "micro.codec.Frame": - gfile.P(`errmap["`, rsp.Name, `"] = &`, microCodecPackage.Ident("Frame"), "{}") - case "micro.errors.Error": - gfile.P(`errmap["`, rsp.Name, `"] = &`, microErrorsPackage.Ident("Error"), "{}") - default: - ident, err := g.getGoIdentByXref(strings.TrimPrefix(schema.XRef, ".")) - if err != nil { - log.Printf("cant find message by ref %s\n", schema.XRef) - continue - } - gfile.P(`errmap["`, rsp.Name, `"] = &`, gfile.QualifiedGoIdent(ident), "{}") - } - } - } - } - gfile.P("opts = append(opts,") - gfile.P(microClientHttpPackage.Ident("ErrorMap"), "(errmap),") - gfile.P(")") - } - if proto.HasExtension(method.Desc.Options(), v3.E_Openapiv3Operation) { - opts := proto.GetExtension(method.Desc.Options(), v3.E_Openapiv3Operation) - if opts != nil { - r := opts.(*v3.Operation) - if r.Responses == nil { - goto labelMethod - } - resps := r.Responses.ResponseOrReference - if r.Responses.GetDefault() != nil { - resps = append(resps, &v3.NamedResponseOrReference{Name: "default", Value: r.Responses.GetDefault()}) - } - gfile.P("errmap := make(map[string]interface{}, ", len(resps), ")") - for _, rsp := range resps { - if schema := rsp.Value.GetReference(); schema != nil { - xref := schema.XRef - if strings.HasPrefix(xref, "."+string(service.Desc.ParentFile().Package())+".") { - xref = strings.TrimPrefix(xref, "."+string(service.Desc.ParentFile().Package())+".") - } - if xref[0] == '.' { - xref = xref[1:] - } - switch xref { - case "micro.codec.Frame": - gfile.P(`errmap["`, rsp.Name, `"] = &`, microCodecPackage.Ident("Frame"), "{}") - case "micro.errors.Error": - gfile.P(`errmap["`, rsp.Name, `"] = &`, microErrorsPackage.Ident("Error"), "{}") - default: - ident, err := g.getGoIdentByXref(strings.TrimPrefix(schema.XRef, ".")) - if err != nil { - log.Printf("cant find message by ref %s\n", schema.XRef) - continue - } - gfile.P(`errmap["`, rsp.Name, `"] = &`, gfile.QualifiedGoIdent(ident), "{}") - } - } - } - } - gfile.P("opts = append(opts,") - gfile.P(microClientHttpPackage.Ident("ErrorMap"), "(errmap),") - gfile.P(")") - } - - labelMethod: - if proto.HasExtension(method.Desc.Options(), api_options.E_Http) { - gfile.P("opts = append(opts,") - endpoints, _ := generateEndpoints(method) - path, method, body := getEndpoint(endpoints[0]) - if vmethod, ok := httpMethodMap[method]; ok { - gfile.P(microClientHttpPackage.Ident("Method"), `(`, httpPackage.Ident(vmethod), `),`) - } else { - gfile.P(microClientHttpPackage.Ident("Method"), `("`, method, `"),`) - } - gfile.P(microClientHttpPackage.Ident("Path"), `("`, path, `"),`) - if body != "" { - gfile.P(microClientHttpPackage.Ident("Body"), `("`, body, `"),`) - } - gfile.P(")") - } - - parameters := make(map[string]map[string]string) - // Build a list of header parameters. - e2opt := proto.GetExtension(method.Desc.Options(), v2.E_Openapiv2Operation) - if e2opt != nil && e2opt != v2.E_Openapiv2Operation.InterfaceOf(v2.E_Openapiv2Operation.Zero()) { - opt := e2opt.(*v2.Operation) - for _, paramOrRef := range opt.Parameters { - parameter := paramOrRef.GetParameter() - // NonBodyParameter() - if parameter == nil { - continue - } - nonBodyParameter := parameter.GetNonBodyParameter() - if nonBodyParameter == nil { - continue - } - headerParameter := nonBodyParameter.GetHeaderParameterSubSchema() - if headerParameter.In != "header" && headerParameter.In != "cookie" { - continue - } - in, ok := parameters[headerParameter.In] - if !ok { - in = make(map[string]string) - parameters[headerParameter.In] = in - } - in[headerParameter.Name] = fmt.Sprintf("%v", headerParameter.Required) - } - } - e3opt := proto.GetExtension(method.Desc.Options(), v3.E_Openapiv3Operation) - if e3opt != nil && e3opt != v3.E_Openapiv3Operation.InterfaceOf(v3.E_Openapiv3Operation.Zero()) { - opt := e3opt.(*v3.Operation) - for _, paramOrRef := range opt.Parameters { - - parameter := paramOrRef.GetParameter() - if parameter == nil { - continue - } - if parameter.In != "header" && parameter.In != "cookie" { - continue - } - in, ok := parameters[parameter.In] - if !ok { - in = make(map[string]string) - parameters[parameter.In] = in - } - in[parameter.Name] = fmt.Sprintf("%v", parameter.Required) - } - } - - if len(parameters) > 0 { - gfile.P("opts = append(opts,") - for pk, pv := range parameters { - params := make([]string, 0, len(pv)/2) - for k, v := range pv { - params = append(params, k, v) - } - gfile.P(microClientHttpPackage.Ident(strings.Title(pk)), `("`, strings.Join(params, `" ,"`), `"),`) - } - gfile.P(")") - } - } - - if rule, ok := getMicroApiMethod(method); ok { - if rule.Timeout != "" { - td, err := time.ParseDuration(rule.Timeout) - if err != nil { - log.Printf("parse duration error %s\n", err.Error()) - } else { - gfile.P("td := ", timePackage.Ident("Duration"), "(", td.Nanoseconds(), ")") - gfile.P("opts = append(opts, ", microClientPackage.Ident("WithRequestTimeout"), "(td))") - } - } - } - - if !method.Desc.IsStreamingServer() && !method.Desc.IsStreamingClient() { - gfile.P("rsp := &", gfile.QualifiedGoIdent(method.Output.GoIdent), "{}") - gfile.P(`err := c.c.Call(ctx, c.c.NewRequest(c.name, "`, methodName, `", req), rsp, opts...)`) - gfile.P("if err != nil {") - gfile.P("return nil, err") - gfile.P("}") - gfile.P("return rsp, nil") - gfile.P("}") - gfile.P() - continue - } - - gfile.P(`stream, err := c.c.Stream(ctx, c.c.NewRequest(c.name, "`, methodName, `", &`, gfile.QualifiedGoIdent(method.Input.GoIdent), `{}), opts...)`) - gfile.P("if err != nil {") - gfile.P("return nil, err") - gfile.P("}") - - if !method.Desc.IsStreamingClient() { - gfile.P("if err := stream.Send(req); err != nil {") - gfile.P("return nil, err") - gfile.P("}") - } - gfile.P("return &", unexport(serviceName), "Client", method.GoName, "{stream}, nil") - gfile.P("}") - gfile.P() - - if method.Desc.IsStreamingServer() || method.Desc.IsStreamingClient() { - gfile.P("type ", unexport(serviceName), "Client", method.GoName, " struct {") - gfile.P("stream ", microClientPackage.Ident("Stream")) - gfile.P("}") - } - - if method.Desc.IsStreamingClient() && !method.Desc.IsStreamingServer() { - gfile.P("func (s *", unexport(serviceName), "Client", method.GoName, ") CloseAndRecv() (*", gfile.QualifiedGoIdent(method.Output.GoIdent), ", error) {") - gfile.P("msg := &", gfile.QualifiedGoIdent(method.Output.GoIdent), "{}") - gfile.P("err := s.RecvMsg(msg)") - gfile.P("if err == nil {") - gfile.P("err = s.Close()") - gfile.P("}") - gfile.P("if err != nil {") - gfile.P("return nil, err") - gfile.P("}") - gfile.P("return msg, nil") - gfile.P("}") - } - - gfile.P() - gfile.P("func (s *", unexport(serviceName), "Client", method.GoName, ") Close() error {") - gfile.P("return s.stream.Close()") - gfile.P("}") - gfile.P() - gfile.P("func (s *", unexport(serviceName), "Client", method.GoName, ") CloseSend() error {") - gfile.P("return s.stream.CloseSend()") - gfile.P("}") - gfile.P() - gfile.P("func (s *", unexport(serviceName), "Client", method.GoName, ") Context() ", contextPackage.Ident("Context"), " {") - gfile.P("return s.stream.Context()") - gfile.P("}") - gfile.P() - gfile.P("func (s *", unexport(serviceName), "Client", method.GoName, ") SendMsg(msg interface{}) error {") - gfile.P("return s.stream.Send(msg)") - gfile.P("}") - gfile.P() - gfile.P("func (s *", unexport(serviceName), "Client", method.GoName, ") RecvMsg(msg interface{}) error {") - gfile.P("return s.stream.Recv(msg)") - gfile.P("}") - gfile.P() - - if method.Desc.IsStreamingClient() { - gfile.P("func (s *", unexport(serviceName), "Client", method.GoName, ") Header() ", microMetadataPackage.Ident("Metadata"), "{") - gfile.P("return s.stream.Response().Header()") - gfile.P("}") - gfile.P() - - gfile.P("func (s *", unexport(serviceName), "Client", method.GoName, ") Send(msg *", gfile.QualifiedGoIdent(method.Input.GoIdent), ") error {") - gfile.P("return s.stream.Send(msg)") - gfile.P("}") - gfile.P() - } - - if method.Desc.IsStreamingServer() { - gfile.P("func (s *", unexport(serviceName), "Client", method.GoName, ") Recv() (*", gfile.QualifiedGoIdent(method.Output.GoIdent), ", error) {") - gfile.P("msg := &", gfile.QualifiedGoIdent(method.Output.GoIdent), "{}") - gfile.P("if err := s.stream.Recv(msg); err != nil {") - gfile.P("return nil, err") - gfile.P("}") - gfile.P("return msg, nil") - gfile.P("}") - gfile.P() - } - } -} - -func (g *Generator) generateServiceServer(gfile *protogen.GeneratedFile, file *protogen.File, service *protogen.Service) { - serviceName := getServiceName(service) - gfile.P("type ", unexport(serviceName), "Server struct {") - if g.standalone { - gfile.P(file.GoImportPath.Ident(serviceName), "Server") - } else { - gfile.P(serviceName, "Server") - } - gfile.P("}") - gfile.P() -} - -func (g *Generator) generateServiceServerMethods(gfile *protogen.GeneratedFile, service *protogen.Service) { - serviceName := getServiceName(service) - for _, method := range service.Methods { - generateServerFuncSignature(gfile, serviceName, method, true) - if rule, ok := getMicroApiMethod(method); ok { - if rule.Timeout != "" { - td, err := time.ParseDuration(rule.Timeout) - if err != nil { - log.Printf("parse duration error %s\n", err.Error()) - } else { - gfile.P("var cancel ", contextPackage.Ident("CancelFunc")) - gfile.P("td := ", timePackage.Ident("Duration"), "(", td.Nanoseconds(), ")") - gfile.P("ctx, cancel = ", contextPackage.Ident("WithTimeout"), "(ctx, ", "td", ")") - gfile.P("defer cancel()") - } - } - } - if method.Desc.IsStreamingClient() || method.Desc.IsStreamingServer() { - if !method.Desc.IsStreamingClient() { - gfile.P("msg := &", gfile.QualifiedGoIdent(method.Input.GoIdent), "{}") - gfile.P("if err := stream.Recv(msg); err != nil {") - gfile.P("return err") - gfile.P("}") - gfile.P("return h.", serviceName, "Server.", method.GoName, "(ctx, msg, &", unexport(serviceName), method.GoName, "Stream{stream})") - } else { - gfile.P("return h.", serviceName, "Server.", method.GoName, "(ctx, &", unexport(serviceName), method.GoName, "Stream{stream})") - } - } else { - parameters := make(map[string]map[string]string) - // Build a list of header parameters. - e2opt := proto.GetExtension(method.Desc.Options(), v2.E_Openapiv2Operation) - if e2opt != nil && e2opt != v2.E_Openapiv2Operation.InterfaceOf(v2.E_Openapiv2Operation.Zero()) { - opt := e2opt.(*v2.Operation) - for _, paramOrRef := range opt.Parameters { - parameter := paramOrRef.GetParameter() - // NonBodyParameter() - if parameter == nil { - continue - } - nonBodyParameter := parameter.GetNonBodyParameter() - if nonBodyParameter == nil { - continue - } - headerParameter := nonBodyParameter.GetHeaderParameterSubSchema() - if headerParameter.In != "header" && headerParameter.In != "cookie" { - continue - } - in, ok := parameters[headerParameter.In] - if !ok { - in = make(map[string]string) - parameters[headerParameter.In] = in - } - in[headerParameter.Name] = fmt.Sprintf("%v", headerParameter.Required) - } - } - e3opt := proto.GetExtension(method.Desc.Options(), v3.E_Openapiv3Operation) - if e3opt != nil && e3opt != v3.E_Openapiv3Operation.InterfaceOf(v3.E_Openapiv3Operation.Zero()) { - opt := e3opt.(*v3.Operation) - for _, paramOrRef := range opt.Parameters { - parameter := paramOrRef.GetParameter() - if parameter == nil { - continue - } - if parameter.In != "header" && parameter.In != "cookie" { - continue - } - in, ok := parameters[parameter.In] - if !ok { - in = make(map[string]string) - parameters[parameter.In] = in - } - in[parameter.Name] = fmt.Sprintf("%v", parameter.Required) - } - } - - if len(parameters) > 0 { - gfile.P(microServerHttpPackage.Ident("FillRequest"), `(ctx, req, `) - for pk, pv := range parameters { - params := make([]string, 0, len(pv)/2) - for k, v := range pv { - params = append(params, k, v) - } - gfile.P(microServerHttpPackage.Ident(strings.Title(pk)), `("`, strings.Join(params, `" ,"`), `"),`) - } - gfile.P(")") - } - gfile.P("return h.", serviceName, "Server.", method.GoName, "(ctx, req, rsp)") - } - gfile.P("}") - gfile.P() - - if method.Desc.IsStreamingClient() || method.Desc.IsStreamingServer() { - gfile.P("type ", unexport(serviceName), method.GoName, "Stream struct {") - gfile.P("stream ", microServerPackage.Ident("Stream")) - gfile.P("}") - } - - if method.Desc.IsStreamingClient() && !method.Desc.IsStreamingServer() { - gfile.P("func (s *", unexport(serviceName), method.GoName, "Stream) SendAndClose(msg *", gfile.QualifiedGoIdent(method.Output.GoIdent), ") error {") - gfile.P("err := s.SendMsg(msg)") - gfile.P("if err == nil {") - gfile.P("err = s.stream.Close()") - gfile.P("}") - gfile.P("return err") - gfile.P("}") - } - - if method.Desc.IsStreamingClient() || method.Desc.IsStreamingServer() { - gfile.P("func (s *", unexport(serviceName), method.GoName, "Stream) Close() error {") - gfile.P("return s.stream.Close()") - gfile.P("}") - gfile.P() - - gfile.P("func (s *", unexport(serviceName), method.GoName, "Stream) Context() ", contextPackage.Ident("Context"), " {") - gfile.P("return s.stream.Context()") - gfile.P("}") - gfile.P() - - gfile.P("func (s *", unexport(serviceName), method.GoName, "Stream) SendMsg(msg interface{}) error {") - gfile.P("return s.stream.Send(msg)") - gfile.P("}") - gfile.P() - - gfile.P("func (s *", unexport(serviceName), method.GoName, "Stream) RecvMsg(msg interface{}) error {") - gfile.P("return s.stream.Recv(msg)") - gfile.P("}") - gfile.P() - - if method.Desc.IsStreamingServer() { - gfile.P("func (s *", unexport(serviceName), method.GoName, "Stream) Send(msg *", gfile.QualifiedGoIdent(method.Output.GoIdent), ") error {") - gfile.P("return s.stream.Send(msg)") - gfile.P("}") - gfile.P() - } - - if method.Desc.IsStreamingClient() { - gfile.P("func (s *", unexport(serviceName), method.GoName, "Stream) Recv() (*", gfile.QualifiedGoIdent(method.Input.GoIdent), ", error) {") - gfile.P("msg := &", gfile.QualifiedGoIdent(method.Input.GoIdent), "{}") - gfile.P("if err := s.stream.Recv(msg); err != nil {") - gfile.P("return nil, err") - gfile.P("}") - gfile.P("return msg, nil") - gfile.P("}") - gfile.P() - } - } - - } -} - -func (g *Generator) generateServiceRegister(gfile *protogen.GeneratedFile, file *protogen.File, service *protogen.Service, component string) { - serviceName := getServiceName(service) - if g.standalone { - gfile.P("func Register", serviceName, "Server(s ", microServerPackage.Ident("Server"), ", sh ", file.GoImportPath.Ident(serviceName), "Server, opts ...", microOptionsPackage.Ident("Option"), ") error {") - } else { - gfile.P("func Register", serviceName, "Server(s ", microServerPackage.Ident("Server"), ", sh ", serviceName, "Server, opts ...", microOptionsPackage.Ident("Option"), ") error {") - } - gfile.P("type ", unexport(serviceName), " interface {") - for _, method := range service.Methods { - generateServerSignature(gfile, serviceName, method, true) - } - gfile.P("}") - gfile.P("type ", serviceName, " struct {") - gfile.P(unexport(serviceName)) - gfile.P("}") - gfile.P("h := &", unexport(serviceName), "Server{sh}") - gfile.P("var nopts []", microOptionsPackage.Ident("Option")) - if component == "http" { - // if g.standalone { - // gfile.P("nopts = append(nopts, ", microServerHttpPackage.Ident("HandlerEndpoints"), "(", file.GoImportPath.Ident(serviceName), "ServerEndpoints))") - // } else { - gfile.P("nopts = append(nopts, ", microServerHttpPackage.Ident("HandlerEndpoints"), "(", serviceName, "ServerEndpoints))") - // } - } - gfile.P("return s.Handle(&", serviceName, "{h}, append(nopts, opts...)...)") - gfile.P("}") -} - -func generateServerFuncSignature(gfile *protogen.GeneratedFile, serviceName string, method *protogen.Method, private bool) { - args := append([]interface{}{}, - "func (h *", unexport(serviceName), "Server) ", method.GoName, - "(ctx ", contextPackage.Ident("Context"), - ) - if private && (method.Desc.IsStreamingClient() || method.Desc.IsStreamingServer()) { - args = append(args, ", stream ", microServerPackage.Ident("Stream")) - } else { - if !method.Desc.IsStreamingClient() { - args = append(args, ", req *", gfile.QualifiedGoIdent(method.Input.GoIdent)) - } - if method.Desc.IsStreamingServer() || method.Desc.IsStreamingClient() { - args = append(args, ", stream ", serviceName, "_", method.GoName, "Stream") - } - if !method.Desc.IsStreamingClient() && !method.Desc.IsStreamingServer() { - args = append(args, ", rsp *", gfile.QualifiedGoIdent(method.Output.GoIdent)) - } - } - args = append(args, ") error {") - gfile.P(args...) -} - -func generateServerSignature(gfile *protogen.GeneratedFile, serviceName string, method *protogen.Method, private bool) { - args := append([]interface{}{}, - method.GoName, - "(ctx ", contextPackage.Ident("Context"), - ) - if private && (method.Desc.IsStreamingClient() || method.Desc.IsStreamingServer()) { - args = append(args, ", stream ", microServerPackage.Ident("Stream")) - } else { - if !method.Desc.IsStreamingClient() { - args = append(args, ", req *", gfile.QualifiedGoIdent(method.Input.GoIdent)) - } - if method.Desc.IsStreamingServer() || method.Desc.IsStreamingClient() { - args = append(args, ", stream ", serviceName, "_", method.GoName, "Stream") - } - if !method.Desc.IsStreamingClient() && !method.Desc.IsStreamingServer() { - args = append(args, ", rsp *", gfile.QualifiedGoIdent(method.Output.GoIdent)) - } - } - args = append(args, ") error") - gfile.P(args...) -} - -func (g *Generator) generateClientFuncSignature(gfile *protogen.GeneratedFile, serviceName string, method *protogen.Method) { - args := append([]interface{}{}, - "func (c *", - unexport(serviceName), - "Client) ", - method.GoName, - "(ctx ", contextPackage.Ident("Context"), ", ", - ) - if !method.Desc.IsStreamingClient() { - args = append(args, "req *", gfile.QualifiedGoIdent(method.Input.GoIdent), ", ") - } - args = append(args, "opts ...", microOptionsPackage.Ident("Option"), ") (") - if !method.Desc.IsStreamingClient() && !method.Desc.IsStreamingServer() { - args = append(args, "*", gfile.QualifiedGoIdent(method.Output.GoIdent)) - } else { - args = append(args, gfile.QualifiedGoIdent(protogen.GoIdent{GoName: serviceName + "_" + method.GoName + "Client", GoImportPath: method.Output.GoIdent.GoImportPath})) - } - args = append(args, ", error) {") - gfile.P(args...) -} - -func generateClientSignature(gfile *protogen.GeneratedFile, serviceName string, method *protogen.Method) { - args := append([]interface{}{}, - method.GoName, - "(ctx ", contextPackage.Ident("Context"), ", ", - ) - if !method.Desc.IsStreamingClient() { - args = append(args, "req *", gfile.QualifiedGoIdent(method.Input.GoIdent), ", ") - } - args = append(args, "opts ...", microOptionsPackage.Ident("Option"), ") (") - if !method.Desc.IsStreamingClient() && !method.Desc.IsStreamingServer() { - args = append(args, "*", gfile.QualifiedGoIdent(method.Output.GoIdent)) - } else { - args = append(args, serviceName, "_", method.GoName, "Client") - } - args = append(args, ", error)") - gfile.P(args...) -} - -func (g *Generator) generateServiceClientInterface(gfile *protogen.GeneratedFile, service *protogen.Service) { - serviceName := getServiceName(service) - gfile.P("type ", serviceName, "Client interface {") - for _, method := range service.Methods { - generateClientSignature(gfile, serviceName, method) - } - gfile.P("}") - gfile.P() -} - -func (g *Generator) generateServiceServerInterface(gfile *protogen.GeneratedFile, service *protogen.Service) { - serviceName := getServiceName(service) - gfile.P("type ", serviceName, "Server interface {") - for _, method := range service.Methods { - generateServerSignature(gfile, serviceName, method, false) - } - gfile.P("}") - gfile.P() -} - -func (g *Generator) generateServiceClientStreamInterface(gfile *protogen.GeneratedFile, service *protogen.Service) { - serviceName := getServiceName(service) - for _, method := range service.Methods { - if !method.Desc.IsStreamingClient() && !method.Desc.IsStreamingServer() { - continue - } - methodName := method.GoName - gfile.P("type ", serviceName, "_", methodName, "Client interface {") - gfile.P("Context() ", contextPackage.Ident("Context")) - gfile.P("SendMsg(msg interface{}) error") - gfile.P("RecvMsg(msg interface{}) error") - if method.Desc.IsStreamingClient() && !method.Desc.IsStreamingServer() { - gfile.P("CloseAndRecv() (*", gfile.QualifiedGoIdent(method.Output.GoIdent), ", error)") - gfile.P("CloseSend() error") - } - gfile.P("Close() error") - if method.Desc.IsStreamingClient() { - gfile.P("Header() ", microMetadataPackage.Ident("Metadata")) - gfile.P("Send(msg *", gfile.QualifiedGoIdent(method.Input.GoIdent), ") error") - } - if method.Desc.IsStreamingServer() { - gfile.P("Recv() (*", gfile.QualifiedGoIdent(method.Output.GoIdent), ", error)") - } - gfile.P("}") - gfile.P() - } -} - -func (g *Generator) generateServiceServerStreamInterface(gfile *protogen.GeneratedFile, service *protogen.Service) { - serviceName := getServiceName(service) - for _, method := range service.Methods { - if !method.Desc.IsStreamingClient() && !method.Desc.IsStreamingServer() { - continue - } - methodName := method.GoName - gfile.P("type ", serviceName, "_", methodName, "Stream interface {") - gfile.P("Context() ", contextPackage.Ident("Context")) - gfile.P("SendMsg(msg interface{}) error") - gfile.P("RecvMsg(msg interface{}) error") - if method.Desc.IsStreamingClient() && !method.Desc.IsStreamingServer() { - gfile.P("SendAndClose(msg *", gfile.QualifiedGoIdent(method.Output.GoIdent), ") error") - // gfile.P("CloseSend() error") - } - gfile.P("Close() error") - if method.Desc.IsStreamingClient() { - gfile.P("Recv() (*", gfile.QualifiedGoIdent(method.Input.GoIdent), ", error)") - } - if method.Desc.IsStreamingServer() { - gfile.P("Send(msg *", gfile.QualifiedGoIdent(method.Output.GoIdent), ") error") - } - gfile.P("}") - gfile.P() - } -} - -func generateEndpoints(method *protogen.Method) ([]*api_options.HttpRule, bool) { - if method.Desc.Options() == nil { - return nil, false - } - - if !proto.HasExtension(method.Desc.Options(), api_options.E_Http) { - return nil, false - } - - r := proto.GetExtension(method.Desc.Options(), api_options.E_Http) - if r == nil { - return nil, false - } - - rule := r.(*api_options.HttpRule) - rules := []*api_options.HttpRule{rule} - rules = append(rules, rule.GetAdditionalBindings()...) - - return rules, method.Desc.IsStreamingServer() || method.Desc.IsStreamingClient() -} - -func getMicroApiMethod(method *protogen.Method) (*api_options.MicroMethod, bool) { - if method.Desc.Options() == nil { - return nil, false - } - - if !proto.HasExtension(method.Desc.Options(), api_options.E_MicroMethod) { - return nil, false - } - - r := proto.GetExtension(method.Desc.Options(), api_options.E_MicroMethod) - if r == nil { - return nil, false - } - - rule := r.(*api_options.MicroMethod) - return rule, true -} - -func getMicroApiService(service *protogen.Service) (*api_options.MicroService, bool) { - if service.Desc.Options() == nil { - return nil, false - } - - if !proto.HasExtension(service.Desc.Options(), api_options.E_MicroService) { - return nil, false - } - - r := proto.GetExtension(service.Desc.Options(), api_options.E_MicroService) - if r == nil { - return nil, false - } - - rule := r.(*api_options.MicroService) - return rule, true -} - -func getEndpoint(rule *api_options.HttpRule) (string, string, string) { - var meth string - var path string - var body string - - switch { - case len(rule.GetDelete()) > 0: - meth = "DELETE" - path = rule.GetDelete() - case len(rule.GetGet()) > 0: - meth = "GET" - path = rule.GetGet() - case len(rule.GetPatch()) > 0: - meth = "PATCH" - path = rule.GetPatch() - case len(rule.GetPost()) > 0: - meth = "POST" - path = rule.GetPost() - case len(rule.GetPut()) > 0: - meth = "PUT" - path = rule.GetPut() - case rule.GetCustom() != nil: - crule := rule.GetCustom() - meth = crule.Kind - path = crule.Path - } - - body = rule.GetBody() - return path, meth, body -} - -func generateEndpoint(gfile *protogen.GeneratedFile, serviceName string, methodName string, rule *api_options.HttpRule, streaming bool) { - path, meth, body := getEndpoint(rule) - gfile.P("Name:", fmt.Sprintf(`"%s.%s",`, serviceName, methodName)) - gfile.P("Path:", fmt.Sprintf(`[]string{"%s"},`, path)) - //if vmethod, ok := httpMethodMap[meth]; ok { - // gfile.P("Method:", `[]string{`, httpPackage.Ident(vmethod), `},`) - //} else { - gfile.P("Method:", fmt.Sprintf(`[]string{"%s"},`, meth)) - // } - if len(rule.GetGet()) == 0 && body != "" { - gfile.P("Body:", fmt.Sprintf(`"%s",`, body)) - } - if streaming { - gfile.P("Stream: true,") - } - gfile.P(`Handler: "rpc",`) -} - -func (g *Generator) getGoIdentByXref(xref string) (protogen.GoIdent, error) { - idx := strings.LastIndex(xref, ".") - pkg := xref[:idx] - msg := xref[idx+1:] - for _, file := range g.plugin.Files { - if strings.Compare(pkg, *(file.Proto.Package)) != 0 { - continue - } - if ident, err := getGoIdentByMessage(file.Messages, msg); err == nil { - return ident, nil - } - } - return protogen.GoIdent{}, fmt.Errorf("not found") -} - -func (g *Generator) getMessageByXref(xref string) (*protogen.Message, error) { - idx := strings.LastIndex(xref, ".") - pkg := xref[:idx] - msg := xref[idx+1:] - for _, file := range g.plugin.Files { - if strings.Compare(pkg, *(file.Proto.Package)) != 0 { - continue - } - if pmsg, err := getProtoMessage(file.Messages, msg); err == nil { - return pmsg, nil - } - } - return nil, fmt.Errorf("not found") -} - -func getProtoMessage(messages []*protogen.Message, msg string) (*protogen.Message, error) { - for _, message := range messages { - if strings.Compare(msg, message.GoIdent.GoName) == 0 { - return message, nil - } - if len(message.Messages) > 0 { - if pmsg, err := getProtoMessage(message.Messages, msg); err == nil { - return pmsg, nil - } - } - } - return nil, fmt.Errorf("not found") -} - -func getGoIdentByMessage(messages []*protogen.Message, msg string) (protogen.GoIdent, error) { - for _, message := range messages { - if strings.Compare(msg, message.GoIdent.GoName) == 0 { - return message.GoIdent, nil - } - if len(message.Messages) > 0 { - if ident, err := getGoIdentByMessage(message.Messages, msg); err == nil { - return ident, nil - } - } - } - return protogen.GoIdent{}, fmt.Errorf("not found") -} - -func (g *Generator) generateServiceDesc(gfile *protogen.GeneratedFile, file *protogen.File, service *protogen.Service) { - serviceName := getServiceName(service) - - gfile.P("// ", serviceName, "_ServiceDesc", " is the ", grpcPackage.Ident("ServiceDesc"), " for ", serviceName, " service.") - gfile.P("// It's only intended for direct use with ", grpcPackage.Ident("RegisterService"), ",") - gfile.P("// and not to be introspected or modified (even as a copy)") - gfile.P("var ", serviceName, "_ServiceDesc", " = ", grpcPackage.Ident("ServiceDesc"), " {") - gfile.P("ServiceName: ", strconv.Quote(string(service.Desc.FullName())), ",") - gfile.P("HandlerType: (*", serviceName, "Server)(nil),") - gfile.P("Methods: []", grpcPackage.Ident("MethodDesc"), "{") - for _, method := range service.Methods { - if method.Desc.IsStreamingClient() || method.Desc.IsStreamingServer() { - continue - } - gfile.P("{") - gfile.P("MethodName: ", strconv.Quote(string(method.Desc.Name())), ",") - gfile.P("Handler: ", method.GoName, ",") - gfile.P("},") - } - gfile.P("},") - gfile.P("Streams: []", grpcPackage.Ident("StreamDesc"), "{") - for _, method := range service.Methods { - if !method.Desc.IsStreamingClient() && !method.Desc.IsStreamingServer() { - continue - } - gfile.P("{") - gfile.P("StreamName: ", strconv.Quote(string(method.Desc.Name())), ",") - gfile.P("Handler: ", method.GoName, ",") - if method.Desc.IsStreamingServer() { - gfile.P("ServerStreams: true,") - } - if method.Desc.IsStreamingClient() { - gfile.P("ClientStreams: true,") - } - gfile.P("},") - } - gfile.P("},") - gfile.P("Metadata: \"", file.Desc.Path(), "\",") - gfile.P("}") - gfile.P() -} - -func (g *Generator) generateServiceName(gfile *protogen.GeneratedFile, service *protogen.Service) { - serviceName := getServiceName(service) - gfile.P("var (") - gfile.P(serviceName, "Name", "=", `"`, serviceName, `"`) - gfile.P(")") -} - -func (g *Generator) generateServiceEndpoints(gfile *protogen.GeneratedFile, service *protogen.Service, component string) { - if component != "http" { - return - } - serviceName := getServiceName(service) - - gfile.P("var (") - gfile.P(serviceName, "ServerEndpoints = []", microServerHttpPackage.Ident("EndpointMetadata"), "{") - - for _, method := range service.Methods { - if proto.HasExtension(method.Desc.Options(), api_options.E_Http) { - if endpoints, streaming := generateEndpoints(method); endpoints != nil { - for _, ep := range endpoints { - epath, emethod, ebody := getEndpoint(ep) - gfile.P("{") - gfile.P(`Name: "`, serviceName+"."+method.GoName, `",`) - gfile.P(`Path: "`, epath, `",`) - gfile.P(`Method: "`, emethod, `",`) - gfile.P(`Body: "`, ebody, `",`) - gfile.P(`Stream: `, streaming, `,`) - gfile.P("},") - } - } - } - } - - gfile.P("}") - gfile.P(")") -} - -func getServiceName(s *protogen.Service) string { - if strings.HasSuffix(s.GoName, "Service") { - return s.GoName - } - return s.GoName + "Service" -} - -func (g *Generator) writeErrors(plugin *protogen.Plugin) error { - errorsMap := make(map[string]struct{}) - - for _, file := range plugin.Files { - for _, service := range file.Services { - for _, method := range service.Methods { - if method.Desc.Options() != nil { - if proto.HasExtension(method.Desc.Options(), v2.E_Openapiv2Operation) { - opts := proto.GetExtension(method.Desc.Options(), v2.E_Openapiv2Operation) - if opts != nil { - r := opts.(*v2.Operation) - if r.Responses == nil { - continue - } - - for _, rsp := range r.Responses.ResponseCode { - if schema := rsp.Value.GetJsonReference(); schema != nil { - xref := schema.XRef - if xref[0] == '.' { - xref = xref[1:] - } - errorsMap[xref] = struct{}{} - } - } - } - } - if proto.HasExtension(method.Desc.Options(), v3.E_Openapiv3Operation) { - opts := proto.GetExtension(method.Desc.Options(), v3.E_Openapiv3Operation) - if opts != nil { - r := opts.(*v3.Operation) - if r.Responses == nil { - continue - } - resps := r.Responses.ResponseOrReference - if r.Responses.GetDefault() != nil { - resps = append(resps, &v3.NamedResponseOrReference{Name: "default", Value: r.Responses.GetDefault()}) - } - for _, rsp := range resps { - if schema := rsp.Value.GetReference(); schema != nil { - xref := schema.XRef - if xref[0] == '.' { - xref = xref[1:] - } - errorsMap[xref] = struct{}{} - } - } - } - } - } - } - } - } - - var gfile *protogen.GeneratedFile - var importPath protogen.GoImportPath - - if len(errorsMap) > 0 { - - var packageName string - - for _, file := range plugin.Files { - if !file.Generate { - continue - } - if len(file.Services) == 0 { - continue - } - packageName = string(file.GoPackageName) - importPath = file.GoImportPath - break - } - - if g.standalone { - importPath = "." - } - - gfile = plugin.NewGeneratedFile("micro_errors.pb.go", importPath) - - gfile.P("// Code generated by protoc-gen-go-micro. DO NOT EDIT.") - gfile.P("// protoc-gen-go-micro version: " + versionComment) - gfile.P() - gfile.P("package ", packageName) - gfile.P() - - gfile.Import(protojsonPackage) - - gfile.P("var (") - gfile.P("marshaler = ", protojsonPackage.Ident("MarshalOptions"), "{}") - gfile.P(")") - } - - for xref := range errorsMap { - msg, err := g.getMessageByXref(xref) - if err != nil { - return err - } - - for _, field := range msg.Fields { - if field.GoName == "Error" { - return fmt.Errorf("failed generate Error() string interface for %s message %s already have Error field", field.Location.SourceFile, msg.Desc.Name()) - } - } - gfile.P(`func (m *`, msg.GoIdent.GoName, `) Error() string {`) - gfile.P(`buf, _ := marshaler.Marshal(m)`) - gfile.P("return string(buf)") - gfile.P(`}`) - // log.Printf("xref %#+v %v\n", msg.GoIdent.GoName, err) - } - - return nil -} diff --git a/variables.go b/variables.go deleted file mode 100644 index f0eb021..0000000 --- a/variables.go +++ /dev/null @@ -1,27 +0,0 @@ -package main - -import "google.golang.org/protobuf/compiler/protogen" - -var ( - reflectPackage = protogen.GoImportPath("reflect") - stringsPackage = protogen.GoImportPath("strings") - fmtPackage = protogen.GoImportPath("fmt") - contextPackage = protogen.GoImportPath("context") - httpPackage = protogen.GoImportPath("net/http") - gorillaMuxPackage = protogen.GoImportPath("github.com/gorilla/mux") - chiPackage = protogen.GoImportPath("github.com/go-chi/chi/v5") - chiMiddlewarePackage = protogen.GoImportPath("github.com/go-chi/chi/v5/middleware") - microMetadataPackage = protogen.GoImportPath("go.unistack.org/micro/v4/metadata") - microClientPackage = protogen.GoImportPath("go.unistack.org/micro/v4/client") - microServerPackage = protogen.GoImportPath("go.unistack.org/micro/v4/server") - microClientHttpPackage = protogen.GoImportPath("go.unistack.org/micro-client-http/v4") - microServerHttpPackage = protogen.GoImportPath("go.unistack.org/micro-server-http/v4") - microCodecPackage = protogen.GoImportPath("go.unistack.org/micro-proto/v4/codec") - microErrorsPackage = protogen.GoImportPath("go.unistack.org/micro/v4/errors") - microOptionsPackage = protogen.GoImportPath("go.unistack.org/micro/v4/options") - grpcPackage = protogen.GoImportPath("google.golang.org/grpc") - protojsonPackage = protogen.GoImportPath("google.golang.org/protobuf/encoding/protojson") - timePackage = protogen.GoImportPath("time") - deprecationComment = "// Deprecated: Do not use." - versionComment = "v4.0.2" -)