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 new file mode 100644 index 0000000..606d6d1 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,31 @@ +--- +name: Bug report +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. + +**To Reproduce** +Steps to reproduce the behavior: +1. Go to '...' +2. Type '....' +3. See error + +**Expected behavior** +A clear and concise description of what you expected to happen. + +**Screenshots / Logs** +If applicable, add screenshots or logs to help explain your problem. + +**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.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 0000000..3f27c3f --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,20 @@ +--- +name: Feature request +about: Suggest an idea for this project +title: "[IDEA] " +labels: enhancement +assignees: '' + +--- + +**Is your feature request related to a problem? Please describe.** +A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] + +**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/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000..ebc63af --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,9 @@ + 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/.gitignore b/.gitignore new file mode 100644 index 0000000..772d6c2 --- /dev/null +++ b/.gitignore @@ -0,0 +1,27 @@ +# Temporary files +*~ +*# +.#* +coverage.txt + +# Vendors +package-lock.json +node_modules/ +vendor/ + +# Binaries for programs and plugins +dist/ +gin-bin +*.exe +*.exe~ +*.dll +*.so +*.dylib + +# Test binary, build with `go test -c` +*.test + +# Output of the go coverage tool, specifically when used with LiteIDE +*.out +/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 052e7ce..59b4d49 100644 --- a/LICENSE +++ b/LICENSE @@ -1,5 +1,6 @@ MIT License +Copyright (c) 2016-2021 Manfred Touron Copyright (c) 2021 Unistack LLC diff --git a/README.md b/README.md new file mode 100644 index 0000000..faca57d --- /dev/null +++ b/README.md @@ -0,0 +1,135 @@ +# `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/). + +--- + +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 +$> 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 +|-----------------------|---------------|---------------------------|----------------------- +| `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 +| `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 **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/chi.go b/chi.go deleted file mode 100644 index 12352e1..0000000 --- a/chi.go +++ /dev/null @@ -1,79 +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" - gfile := plugin.NewGeneratedFile(gname, ".") - - gfile.P("// Code generated by protoc-gen-micro") - gfile.P("package ", file.GoPackageName) - - gfile.P() - gfile.P("import (") - gfile.P(`"context"`) - gfile.P(`"fmt"`) - gfile.P(`"net/http"`) - gfile.P(`"reflect"`) - gfile.P(`"strings"`) - gfile.P(`chi "github.com/go-chi/chi/v4"`) - gfile.P(`middleware "github.com/go-chi/chi/v4/middleware"`) - gfile.P(`micro_api "github.com/unistack-org/micro/v3/api"`) - gfile.P(")") - gfile.P() - - gfile.P("type routeKey struct{}") - - gfile.P("func RouteName(ctx context.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 *chi.Mux, h interface{}, eps []*micro_api.Endpoint) error {") - gfile.P("v := reflect.ValueOf(h)") - gfile.P("if v.NumMethod() < 1 {") - gfile.P(`return fmt.Errorf("handler has no methods: %T", h)`) - gfile.P("}") - gfile.P("for _, ep := range eps {") - gfile.P(`idx := strings.Index(ep.Name, ".")`) - gfile.P("if idx < 1 || len(ep.Name) <= idx {") - gfile.P(`return fmt.Errorf("invalid api.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 fmt.Errorf("invalid handler, method %s not found", name)`) - gfile.P("}") - gfile.P("rh, ok := m.Interface().(func(http.ResponseWriter, *http.Request))") - gfile.P("if !ok {") - gfile.P(`return fmt.Errorf("invalid handler: %#+v", m.Interface())`) - gfile.P("}") - gfile.P("for _, method := range ep.Method {") - gfile.P("r.With(middleware.WithValue(routeKey{}, ep.Name)).MethodFunc(method, ep.Path[0], rh)") - gfile.P("}") - 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/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 c083d57..61d0214 100644 --- a/go.mod +++ b/go.mod @@ -1,9 +1,19 @@ -module github.com/unistack-org/protoc-gen-micro2 +module github.com/unistack-org/protoc-gen-micro/v3 -go 1.16 +go 1.15 require ( + 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 v1.16.0 github.com/grpc-ecosystem/grpc-gateway/v2 v2.2.0 - google.golang.org/genproto v0.0.0-20210207032614-bba0dbe2a9ea + 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-20210222212404-3e1e516060db google.golang.org/protobuf v1.25.0 ) diff --git a/go.sum b/go.sum index a54a321..247c132 100644 --- a/go.sum +++ b/go.sum @@ -33,24 +33,63 @@ cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9 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/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/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/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/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/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/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +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= @@ -64,6 +103,7 @@ github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt 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= @@ -80,6 +120,7 @@ github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw 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= @@ -98,27 +139,79 @@ github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hf 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/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/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.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/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= @@ -127,11 +220,18 @@ 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= @@ -174,11 +274,14 @@ golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR 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= @@ -187,23 +290,30 @@ golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/ 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-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.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= @@ -219,6 +329,7 @@ golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7w 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-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -226,11 +337,15 @@ golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7w 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/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= @@ -274,6 +389,7 @@ golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roY 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= @@ -310,6 +426,7 @@ google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRn 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= @@ -325,18 +442,31 @@ google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfG google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210207032614-bba0dbe2a9ea h1:N98SvVh7Hdle2lgUVFuIkf0B3u29CUakMUQa7Hwz8Wc= +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/genproto v0.0.0-20210219173056-d891e3cb3b5b h1:zTeTu5p/EXQSqNJboHUw32wdNFYQTT9vSc+ibSpCoLk= +google.golang.org/genproto v0.0.0-20210219173056-d891e3cb3b5b/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210222212404-3e1e516060db h1:SHQi2osmct8Y+ngNVppVlyB/WdW+XA9gHs8wPEE2xFY= +google.golang.org/genproto v0.0.0-20210222212404-3e1e516060db/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= @@ -345,6 +475,8 @@ google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKa 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.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= @@ -358,11 +490,22 @@ google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpAD 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= +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-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.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= diff --git a/gorilla.go b/gorilla.go deleted file mode 100644 index ec1921b..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" - gfile := plugin.NewGeneratedFile(gname, ".") - - gfile.P("// Code generated by protoc-gen-micro") - gfile.P("package ", file.GoPackageName) - gfile.P() - - gfile.P("import (") - gfile.P(`"fmt"`) - gfile.P(`"net/http"`) - gfile.P(`"reflect"`) - gfile.P(`"strings"`) - gfile.P() - gfile.P(`micro_api "github.com/unistack-org/micro/v3/api"`) - gfile.P(`mux "github.com/gorilla/mux"`) - gfile.P(")") - gfile.P() - - gfile.P("func RegisterHandlers(r *mux.Router, h interface{}, eps []*micro_api.Endpoint) error {") - gfile.P("v := reflect.ValueOf(h)") - gfile.P("if v.NumMethod() < 1 {") - gfile.P(`return fmt.Errorf("handler has no methods: %T", h)`) - gfile.P("}") - gfile.P("for _, ep := range eps {") - gfile.P(`idx := strings.Index(ep.Name, ".")`) - gfile.P("if idx < 1 || len(ep.Name) <= idx {") - gfile.P(`return fmt.Errorf("invalid api.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 fmt.Errorf("invalid handler, method %s not found", name)`) - gfile.P("}") - gfile.P("rh, ok := m.Interface().(func(http.ResponseWriter, *http.Request))") - gfile.P("if !ok {") - gfile.P(`return fmt.Errorf("invalid handler: %#+v", m.Interface())`) - gfile.P("}") - gfile.P("r.HandleFunc(ep.Path[0], 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 446d817..0000000 --- a/http.go +++ /dev/null @@ -1,137 +0,0 @@ -package main - -import ( - "strings" - - openapi_options "github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv2/options" - "google.golang.org/protobuf/compiler/protogen" - "google.golang.org/protobuf/proto" -) - -type Error struct { - packageName string - types []string -} - -func (g *Generator) httpGenerate(component string, plugin *protogen.Plugin) error { - errors := make(map[string]struct{}) - - for _, file := range plugin.Files { - if !file.Generate { - continue - } - if len(file.Services) == 0 { - continue - } - - gname := file.GeneratedFilenamePrefix + "_micro_" + component + ".pb.go" - gfile := plugin.NewGeneratedFile(gname, ".") - - gfile.P("// Code generated by protoc-gen-micro") - gfile.P("// source: ", *file.Proto.Name) - gfile.P("package ", file.GoPackageName) - - gfile.P() - gfile.P("import (") - gfile.P(`"context"`) - gfile.P() - gfile.P(`micro_api "github.com/unistack-org/micro/v3/api"`) - gfile.P(`micro_client_http "github.com/unistack-org/micro-client-http/v3"`) - gfile.P(`micro_client "github.com/unistack-org/micro/v3/client"`) - gfile.P(`micro_server "github.com/unistack-org/micro/v3/server"`) - gfile.P(")") - gfile.P() - - gfile.P("// Reference imports to suppress errors if they are not otherwise used.") - gfile.P("var (") - gfile.P("_ ", "micro_api.Endpoint") - gfile.P("_ ", "context.Context") - gfile.P(" _ ", "micro_client.Option") - gfile.P(" _ ", "micro_server.Option") - gfile.P(")") - gfile.P() - - for _, service := range file.Services { - generateServiceClient(gfile, service) - generateServiceClientMethods(gfile, service, true) - generateServiceServer(gfile, service) - generateServiceServerMethods(gfile, service) - generateServiceRegister(gfile, service) - if component == "http" { - for k, v := range getErrors(service) { - errors[k] = v - } - } - } - } - - files := make(map[string]*Error) - for _, file := range plugin.Files { - if !file.Generate { - continue - } - - err, ok := files[file.GeneratedFilenamePrefix] - if !ok { - err = &Error{packageName: string(file.GoPackageName)} - } - fok := false - for _, message := range file.Messages { - if _, ok := errors["."+string(message.Desc.FullName())]; ok { - fok = true - err.types = append(err.types, string(message.Desc.FullName())) - } - } - if fok { - files[file.GeneratedFilenamePrefix] = err - } - } - - for file, err := range files { - gfile := plugin.NewGeneratedFile(file+"_micro_errors.pb.go", ".") - generateServiceErrors(gfile, err) - } - - return nil -} - -func getErrors(service *protogen.Service) map[string]struct{} { - errors := make(map[string]struct{}) - - for _, method := range service.Methods { - if method.Desc.Options() == nil { - continue - } - if !proto.HasExtension(method.Desc.Options(), openapi_options.E_Openapiv2Operation) { - continue - } - - opts := proto.GetExtension(method.Desc.Options(), openapi_options.E_Openapiv2Operation) - if opts == nil { - continue - } - - r := opts.(*openapi_options.Operation) - for _, response := range r.Responses { - if response.Schema == nil || response.Schema.JsonSchema == nil { - continue - } - errors[response.Schema.JsonSchema.Ref] = struct{}{} - } - } - - return errors -} - -func generateServiceErrors(gfile *protogen.GeneratedFile, err *Error) { - gfile.P("package ", err.packageName) - gfile.P("import (") - gfile.P(`"fmt"`) - gfile.P(")") - for _, typ := range err.types { - gfile.P("func (err *", typ[strings.LastIndex(typ, ".")+1:], ") Error() string {") - gfile.P(`return fmt.Sprintf("%#v", err)`) - gfile.P("}") - gfile.P() - } -} diff --git a/main.go b/main.go index a44be67..f00b409 100644 --- a/main.go +++ b/main.go @@ -1,67 +1,217 @@ package main import ( - "flag" "fmt" + "go/format" + "io/ioutil" + "log" + "net/url" + "os" "strings" - "google.golang.org/protobuf/compiler/protogen" + "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 ( - flags flag.FlagSet - flagDebug *bool - flagComponents *string - flagPaths *string - flagModule *string + registry *ggdescriptor.Registry // some helpers need access to registry ) -func init() { - flagDebug = flags.Bool("debug", false, "") - flagComponents = flags.String("components", "micro", "") - flagPaths = flag.String("paths", "", "") - flagModule = flag.String("module", "", "") -} +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: flags.Set, + g := generator.New() + + data, err := ioutil.ReadAll(os.Stdin) + if err != nil { + g.Error(err, "reading input") } - g := &Generator{} + if err = proto.Unmarshal(data, g.Request); err != nil { + g.Error(err, "parsing input proto") + } - opts.Run(g.Generate) -} + if len(g.Request.FileToGenerate) == 0 { + g.Fail("no files to generate") + } -type Generator struct { -} + g.CommandLineParameters(g.Request.GetParameter()) -func (g *Generator) Generate(plugin *protogen.Plugin) error { - var err error + // 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) + } + } + } - // Protoc passes a slice of File structs for us to process - for _, component := range strings.Split(*flagComponents, "|") { - switch component { - case "micro": - err = g.microGenerate(component, plugin) - case "http": - err = g.httpGenerate(component, plugin) - case "grpc", "rpc": - err = g.rpcGenerate(component, plugin) - case "gorilla": - err = g.gorillaGenerate(component, plugin) - case "chi": - err = g.chiGenerate(component, plugin) - 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) } - return nil + data, err = proto.Marshal(g.Response) + if err != nil { + g.Error(err, "failed to marshal output proto") + } + + _, err = os.Stdout.Write(data) + if err != nil { + g.Error(err, "failed to write output proto") + } } diff --git a/micro.go b/micro.go deleted file mode 100644 index 8ed1be9..0000000 --- a/micro.go +++ /dev/null @@ -1,52 +0,0 @@ -package main - -import ( - "google.golang.org/protobuf/compiler/protogen" -) - -func (g *Generator) microGenerate(component string, plugin *protogen.Plugin) error { - for _, file := range plugin.Files { - if !file.Generate { - continue - } - if len(file.Services) == 0 { - continue - } - - gname := file.GeneratedFilenamePrefix + "_" + component + ".pb.go" - gfile := plugin.NewGeneratedFile(gname, ".") - - gfile.P("// Code generated by protoc-gen-micro") - gfile.P("// source: ", *file.Proto.Name) - gfile.P("package ", file.GoPackageName) - - gfile.P() - gfile.P("import (") - gfile.P(`"context"`) - gfile.P() - gfile.P(`micro_api "github.com/unistack-org/micro/v3/api"`) - gfile.P(`micro_client "github.com/unistack-org/micro/v3/client"`) - gfile.P(")") - gfile.P() - - gfile.P("// Reference imports to suppress errors if they are not otherwise used.") - gfile.P("var (") - gfile.P("_ ", "micro_api.Endpoint") - gfile.P("_ ", "context.Context") - gfile.P(" _ ", "micro_client.Option") - gfile.P(")") - gfile.P() - - // generate services - for _, service := range file.Services { - generateServiceEndpoints(gfile, service) - generateServiceClientInterface(gfile, service) - generateServiceClientStreamInterface(gfile, service) - generateServiceServerInterface(gfile, service) - generateServiceServerStreamInterface(gfile, service) - } - - } - - return nil -} diff --git a/rpc.go b/rpc.go deleted file mode 100644 index 48035ec..0000000 --- a/rpc.go +++ /dev/null @@ -1,52 +0,0 @@ -package main - -import ( - "google.golang.org/protobuf/compiler/protogen" -) - -func (g *Generator) rpcGenerate(component string, plugin *protogen.Plugin) error { - for _, file := range plugin.Files { - if !file.Generate { - continue - } - if len(file.Services) == 0 { - continue - } - - gname := file.GeneratedFilenamePrefix + "_micro_" + component + ".pb.go" - gfile := plugin.NewGeneratedFile(gname, ".") - - gfile.P("// Code generated by protoc-gen-micro") - gfile.P("// source: ", *file.Proto.Name) - gfile.P("package ", file.GoPackageName) - - gfile.P() - gfile.P("import (") - gfile.P(`"context"`) - gfile.P() - gfile.P(`micro_api "github.com/unistack-org/micro/v3/api"`) - gfile.P(`micro_client "github.com/unistack-org/micro/v3/client"`) - gfile.P(`micro_server "github.com/unistack-org/micro/v3/server"`) - gfile.P(")") - gfile.P() - - gfile.P("// Reference imports to suppress errors if they are not otherwise used.") - gfile.P("var (") - gfile.P("_ ", "micro_api.Endpoint") - gfile.P("_ ", "context.Context") - gfile.P(" _ ", "micro_client.Option") - gfile.P(" _ ", "micro_server.Option") - gfile.P(")") - gfile.P() - - for _, service := range file.Services { - generateServiceClient(gfile, service) - generateServiceClientMethods(gfile, service, false) - generateServiceServer(gfile, service) - generateServiceServerMethods(gfile, service) - generateServiceRegister(gfile, 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 9d2d06e..0000000 --- a/util.go +++ /dev/null @@ -1,450 +0,0 @@ -package main - -import ( - "fmt" - "strings" - - openapi_options "github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv2/options" - api_options "google.golang.org/genproto/googleapis/api/annotations" - "google.golang.org/protobuf/compiler/protogen" - "google.golang.org/protobuf/proto" -) - -func lowerFirst(s string) string { - return strings.ToLower(s[:1]) + s[1:] -} - -func generateServiceClient(gfile *protogen.GeneratedFile, service *protogen.Service) { - serviceName := strings.TrimSuffix(service.GoName, "Service") - gfile.P("type ", lowerFirst(serviceName), "Service struct {") - gfile.P("c micro_client.Client") - gfile.P("name string") - gfile.P("}") - - gfile.P("// New", serviceName, "Service create new service client") - gfile.P("func New", serviceName, "Service(name string, c micro_client.Client) ", serviceName, "Service {") - gfile.P("return &", lowerFirst(serviceName), "Service{c: c, name: name}") - gfile.P("}") - gfile.P() -} - -func generateServiceClientMethods(gfile *protogen.GeneratedFile, service *protogen.Service, http bool) { - serviceName := strings.TrimSuffix(service.GoName, "Service") - for _, method := range service.Methods { - methodName := fmt.Sprintf("%s.%s", serviceName, method.GoName) - gfile.P("func (c *", lowerFirst(serviceName), "Service) ", generateClientSignature(serviceName, method), "{") - - if http && method.Desc.Options() != nil { - if proto.HasExtension(method.Desc.Options(), openapi_options.E_Openapiv2Operation) { - opts := proto.GetExtension(method.Desc.Options(), openapi_options.E_Openapiv2Operation) - if opts != nil { - r := opts.(*openapi_options.Operation) - gfile.P("errmap := make(map[string]interface{}, ", len(r.Responses), ")") - for code, response := range r.Responses { - if response.Schema == nil || response.Schema.JsonSchema == nil { - continue - } - ref := response.Schema.JsonSchema.Ref - if strings.HasPrefix(ref, "."+string(service.Desc.ParentFile().Package())+".") { - ref = strings.TrimPrefix(ref, "."+string(service.Desc.ParentFile().Package())+".") - } - gfile.P(`errmap["`, code, `"] = &`, ref, "{}") - } - } - - gfile.P("opts = append(opts,") - gfile.P("micro_client_http.ErrorMap(errmap),") - - if proto.HasExtension(method.Desc.Options(), api_options.E_Http) { - endpoints, _ := generateEndpoints(method) - path, method, body := getEndpoint(endpoints[0]) - gfile.P(`micro_client_http.Method("`, method, `"),`) - gfile.P(`micro_client_http.Path("`, path, `"),`) - gfile.P(`micro_client_http.Body("`, body, `"),`) - } - - gfile.P(")") - } - } - - if !method.Desc.IsStreamingServer() && !method.Desc.IsStreamingClient() { - gfile.P("rsp := &", method.Output.Desc.Name(), "{}") - 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() - return - } - - gfile.P(`stream, err := c.c.Stream(ctx, c.c.NewRequest(c.name, "`, methodName, `", &`, method.Input.Desc.Name(), `{}), 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 &", lowerFirst(serviceName), "Service", method.GoName, "{stream}, nil") - gfile.P("}") - gfile.P() - - if method.Desc.IsStreamingServer() || method.Desc.IsStreamingClient() { - gfile.P("type ", lowerFirst(serviceName), "Service", method.GoName, " struct {") - gfile.P("stream micro_client.Stream") - gfile.P("}") - } - - if method.Desc.IsStreamingClient() && !method.Desc.IsStreamingServer() { - gfile.P("func (s *", lowerFirst(serviceName), "Service", method.GoName, ") RecvAndClose() (*", method.Output.Desc.Name(), ", error) {") - gfile.P("m := &", method.Output.Desc.Name(), "{}") - gfile.P("err := s.RecvMsg(m)") - 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 m, nil") - gfile.P("}") - } - - gfile.P() - gfile.P("func (s *", lowerFirst(serviceName), "Service", method.GoName, ") Close() error {") - gfile.P("return s.stream.Close()") - gfile.P("}") - gfile.P() - gfile.P("func (s *", lowerFirst(serviceName), "Service", method.GoName, ") Context() context.Context {") - gfile.P("return s.stream.Context()") - gfile.P("}") - gfile.P() - gfile.P("func (s *", lowerFirst(serviceName), "Service", method.GoName, ") SendMsg(m interface{}) error {") - gfile.P("return s.stream.Send(m)") - gfile.P("}") - gfile.P() - gfile.P("func (s *", lowerFirst(serviceName), "Service", method.GoName, ") RecvMsg(m interface{}) error {") - gfile.P("return s.stream.Recv(m)") - gfile.P("}") - gfile.P() - - if method.Desc.IsStreamingClient() { - gfile.P("func (s *", lowerFirst(serviceName), "Service", method.GoName, ") Send(m *", method.Input.Desc.Name(), ") error {") - gfile.P("return s.stream.Send(m)") - gfile.P("}") - gfile.P() - } - - if method.Desc.IsStreamingServer() { - gfile.P("func (s *", lowerFirst(serviceName), "Service", method.GoName, ") Recv() (*", method.Output.Desc.Name(), ", error) {") - gfile.P("m := &", method.Output.Desc.Name(), "{}") - gfile.P("if err := s.stream.Recv(m); err != nil {") - gfile.P("return nil, err") - gfile.P("}") - gfile.P("return m, nil") - gfile.P("}") - gfile.P() - } - } -} - -func generateServiceServer(gfile *protogen.GeneratedFile, service *protogen.Service) { - serviceName := strings.TrimSuffix(service.GoName, "Service") - gfile.P("type ", lowerFirst(serviceName), "Handler struct {") - gfile.P(serviceName, "Handler") - gfile.P("}") - gfile.P() -} - -func generateServiceServerMethods(gfile *protogen.GeneratedFile, service *protogen.Service) { - serviceName := strings.TrimSuffix(service.GoName, "Service") - for _, method := range service.Methods { - //methodName := fmt.Sprintf("%s.%s", serviceName, method.GoName) - gfile.P("func (h *", lowerFirst(serviceName), "Handler) ", generateServerSignature(serviceName, method), "{") - generateServerSignature(serviceName, method) - - if method.Desc.IsStreamingClient() || method.Desc.IsStreamingServer() { - if !method.Desc.IsStreamingClient() { - gfile.P("m := &", method.Input.Desc.Name(), "{}") - gfile.P("if err := stream.Recv(m); err != nil {") - gfile.P("return err") - gfile.P("}") - gfile.P("return h.", serviceName, "Handler.", method.GoName, "(ctx, m, &", lowerFirst(serviceName), method.GoName, ",Stream{stream})") - } else { - gfile.P("return h.", serviceName, "Handler.", method.GoName, "(ctx, &", lowerFirst(serviceName), method.GoName, "Stream{stream})") - } - } else { - gfile.P("return h.", serviceName, "Handler.", method.GoName, "(ctx, req, rsp)") - } - gfile.P("}") - gfile.P() - - if method.Desc.IsStreamingClient() || method.Desc.IsStreamingServer() { - gfile.P("type ", lowerFirst(serviceName), method.GoName, "Stream struct {") - gfile.P("stream micro_server.Stream") - gfile.P("}") - } - - if method.Desc.IsStreamingClient() && !method.Desc.IsStreamingServer() { - gfile.P("func (s *", lowerFirst(serviceName), method.GoName, "Stream) SendAndClose(m *", method.Output.Desc.Name(), ") error {") - gfile.P("err := s.SendMsg(m)") - 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 *", lowerFirst(serviceName), method.GoName, "Stream) Close() error {") - gfile.P("return s.stream.Close()") - gfile.P("}") - gfile.P() - - gfile.P("func (s *", lowerFirst(serviceName), method.GoName, "Stream) Context() context.Context {") - gfile.P("return s.stream.Context()") - gfile.P("}") - gfile.P() - - gfile.P("func (s *", lowerFirst(serviceName), method.GoName, "Stream) SendMsg(m interface{}) error {") - gfile.P("return s.stream.Send(m)") - gfile.P("}") - gfile.P() - - gfile.P("func (s *", lowerFirst(serviceName), method.GoName, "Stream) RecvMsg(m interface{}) error {") - gfile.P("return s.stream.Recv(m)") - gfile.P("}") - gfile.P() - - if method.Desc.IsStreamingServer() { - gfile.P("func (s *", lowerFirst(serviceName), method.GoName, "Stream) Send(m *", method.Output.Desc.Name(), ") error {") - gfile.P("return s.stream.Send(m)") - gfile.P("}") - gfile.P() - } - - if method.Desc.IsStreamingClient() { - gfile.P("func (s *", lowerFirst(serviceName), method.GoName, "Stream) Recv() (*", method.Input.Desc.Name(), ", error) {") - gfile.P("m := &", method.Input.Desc.Name(), "{}") - gfile.P("if err := s.stream.Recv(m); err != nil {") - gfile.P("return nil, err") - gfile.P("}") - gfile.P("return m, nil") - gfile.P("}") - gfile.P() - } - } - - } -} - -func generateServiceRegister(gfile *protogen.GeneratedFile, service *protogen.Service) { - serviceName := strings.TrimSuffix(service.GoName, "Service") - gfile.P("func Register", serviceName, "Handler(s micro_server.Server, sh ", serviceName, "Handler, opts ...micro_server.HandlerOption) error {") - gfile.P("type ", lowerFirst(serviceName), " interface {") - for _, method := range service.Methods { - gfile.P(generateServerSignature(serviceName, method)) - } - gfile.P("}") - gfile.P("type ", serviceName, " struct {") - gfile.P(lowerFirst(serviceName)) - gfile.P("}") - gfile.P("h := &", lowerFirst(serviceName), "Handler{sh}") - gfile.P("for _, endpoint := range New", serviceName, "Endpoints() {") - gfile.P("opts = append(opts, micro_api.WithEndpoint(endpoint))") - gfile.P("}") - gfile.P("return s.Handle(s.NewHandler(&", serviceName, "{h}, opts...))") - gfile.P("}") -} - -func generateServerSignature(serviceName string, method *protogen.Method) string { - methodName := string(method.GoName) - req := []string{"ctx context.Context"} - ret := "error" - - if !method.Desc.IsStreamingClient() { - req = append(req, "req *"+string(method.Input.Desc.Name())) - } - if method.Desc.IsStreamingServer() || method.Desc.IsStreamingClient() { - req = append(req, "stream "+serviceName+"_"+methodName+"Stream") - } - if !method.Desc.IsStreamingClient() && !method.Desc.IsStreamingServer() { - req = append(req, "rsp *"+string(method.Output.Desc.Name())) - } - return methodName + "(" + strings.Join(req, ", ") + ") " + ret -} - -func generateClientSignature(serviceName string, method *protogen.Method) string { - methodName := string(method.GoName) - req := ", req *" + string(method.Input.Desc.Name()) - if method.Desc.IsStreamingClient() { - req = "" - } - rsp := "*" + string(method.Output.Desc.Name()) - if method.Desc.IsStreamingClient() || method.Desc.IsStreamingServer() { - rsp = serviceName + "_" + methodName + "Service" - } - return fmt.Sprintf("%s(ctx context.Context%s, opts ...micro_client.CallOption) (%s, error)", methodName, req, rsp) -} - -func generateServiceClientInterface(gfile *protogen.GeneratedFile, service *protogen.Service) { - serviceName := strings.TrimSuffix(service.GoName, "Service") - gfile.P("type ", serviceName, "Service interface {") - for _, method := range service.Methods { - gfile.P(generateClientSignature(serviceName, method)) - } - gfile.P("}") - gfile.P() -} - -func generateServiceServerInterface(gfile *protogen.GeneratedFile, service *protogen.Service) { - serviceName := strings.TrimSuffix(service.GoName, "Service") - gfile.P("type ", serviceName, "Handler interface {") - for _, method := range service.Methods { - gfile.P(generateServerSignature(serviceName, method)) - } - gfile.P("}") - gfile.P() -} - -func generateServiceClientStreamInterface(gfile *protogen.GeneratedFile, service *protogen.Service) { - serviceName := strings.TrimSuffix(service.GoName, "Service") - for _, method := range service.Methods { - if !method.Desc.IsStreamingClient() && !method.Desc.IsStreamingServer() { - continue - } - methodName := method.GoName - gfile.P("type ", serviceName, "_", methodName, "Service interface {") - gfile.P("Context() context.Context") - gfile.P("SendMsg(msg interface{}) error") - gfile.P("RecvMsg(msg interface{}) error") - if method.Desc.IsStreamingClient() && !method.Desc.IsStreamingServer() { - gfile.P("RecvAndClose() (", method.Output.Desc.Name(), ", error)") - } - gfile.P("Close() error") - if method.Desc.IsStreamingClient() { - gfile.P("Send(msg *", method.Input.Desc.Name(), ") error") - } - if method.Desc.IsStreamingServer() { - gfile.P("Recv() (msg *", method.Output.Desc.Name(), ", error)") - } - } -} - -func generateServiceServerStreamInterface(gfile *protogen.GeneratedFile, service *protogen.Service) { - serviceName := strings.TrimSuffix(service.GoName, "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() context.Context") - gfile.P("SendMsg(msg interface{}) error") - gfile.P("RecvMsg(msg interface{}) error") - if method.Desc.IsStreamingClient() && !method.Desc.IsStreamingServer() { - gfile.P("SendAndClose(msg *", method.Output.Desc.Name(), ") error") - } - gfile.P("Close() error") - if method.Desc.IsStreamingClient() { - gfile.P("Send(msg *", method.Output.Desc.Name(), ") error") - } - if method.Desc.IsStreamingServer() { - gfile.P("Recv() (msg *", method.Input.Desc.Name(), ", error)") - } - } -} - -func generateServiceEndpoints(gfile *protogen.GeneratedFile, service *protogen.Service) { - serviceName := strings.TrimSuffix(service.GoName, "Service") - gfile.P("// New", serviceName, "Endpoints provides api endpoints metdata for ", serviceName, " service") - gfile.P("func New", serviceName, "Endpoints() []*micro_api.Endpoint {") - gfile.P("return []*", "micro_api.Endpoint{") - for _, method := range service.Methods { - if method.Desc.Options() == nil { - continue - } - if proto.HasExtension(method.Desc.Options(), api_options.E_Http) { - endpoints, streaming := generateEndpoints(method) - for _, endpoint := range endpoints { - gfile.P("&", "micro_api.Endpoint{") - generateEndpoint(gfile, serviceName, method.GoName, endpoint, streaming) - gfile.P("},") - } - } - } - gfile.P("}") - 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 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)) - gfile.P("Method:", fmt.Sprintf(`[]string{"%s"},`, meth)) - if len(rule.GetGet()) == 0 { - gfile.P("Body:", fmt.Sprintf(`"%s",`, body)) - } - if streaming { - gfile.P("Stream: true,") - } - gfile.P(`Handler: "rpc",`) - - return -}