Compare commits
36 Commits
| Author | SHA1 | Date |
|---|---|---|
|
|
c54eac28fd | |
|
|
6caf0e77fa | |
|
|
1ad1dc15dd | |
|
|
f575e91b2c | |
|
|
ed672b2bc9 | |
|
|
eab6c910a6 | |
|
|
60e53f304f | |
|
|
f093930c85 | |
|
|
7ad93a42d9 | |
|
|
7155fb6211 | |
|
|
f28d506cea | |
|
|
58ccc6321e | |
|
|
b519ffc959 | |
|
|
3a8fa31879 | |
|
|
614b1687cf | |
|
|
30f87c1323 | |
|
|
78655b4786 | |
|
|
d00c28104b | |
|
|
9e3e083f29 | |
|
|
c32936d71e | |
|
|
f3c8ec2564 | |
|
|
7e1a6c9068 | |
|
|
b9a11e9fea | |
|
|
bc5cf811a0 | |
|
|
fb49f049e6 | |
|
|
cdb43b08fa | |
|
|
56181ba330 | |
|
|
46c38b351a | |
|
|
a05d48d6dd | |
|
|
fc63514da1 | |
|
|
e14d9f769a | |
|
|
239dde4a62 | |
|
|
80e833a557 | |
|
|
6fccd7757e | |
|
|
400fa5f2d3 | |
|
|
0e13e85e65 |
|
|
@ -9,22 +9,22 @@ shared_configs:
|
||||||
# Use the latest 2.1 version of CircleCI pipeline process engine. See: https://circleci.com/docs/2.0/configuration-reference
|
# Use the latest 2.1 version of CircleCI pipeline process engine. See: https://circleci.com/docs/2.0/configuration-reference
|
||||||
version: 2.1
|
version: 2.1
|
||||||
jobs:
|
jobs:
|
||||||
build-1-19:
|
build-1-23:
|
||||||
working_directory: ~/repo
|
working_directory: ~/repo
|
||||||
docker:
|
docker:
|
||||||
- image: cimg/go:1.19
|
- image: cimg/go:1.23
|
||||||
steps: *simple_job_steps
|
steps: *simple_job_steps
|
||||||
|
|
||||||
build-1-20:
|
build-1-24:
|
||||||
working_directory: ~/repo
|
working_directory: ~/repo
|
||||||
docker:
|
docker:
|
||||||
- image: cimg/go:1.20
|
- image: cimg/go:1.24
|
||||||
steps: *simple_job_steps
|
steps: *simple_job_steps
|
||||||
|
|
||||||
build-1-21:
|
build-1-25:
|
||||||
working_directory: ~/repo
|
working_directory: ~/repo
|
||||||
docker:
|
docker:
|
||||||
- image: cimg/go:1.21
|
- image: cimg/go:1.25
|
||||||
steps:
|
steps:
|
||||||
- checkout
|
- checkout
|
||||||
- run:
|
- run:
|
||||||
|
|
@ -32,18 +32,9 @@ jobs:
|
||||||
command: |
|
command: |
|
||||||
make ci
|
make ci
|
||||||
|
|
||||||
# TODO: Need updates to some static analyzer tools to support 1.22. After those
|
|
||||||
# are updated, move the full linting from 1.21 to this latest release.
|
|
||||||
build-1-22:
|
|
||||||
working_directory: ~/repo
|
|
||||||
docker:
|
|
||||||
- image: cimg/go:1.22
|
|
||||||
steps: *simple_job_steps
|
|
||||||
|
|
||||||
workflows:
|
workflows:
|
||||||
pr-build-test:
|
pr-build-test:
|
||||||
jobs:
|
jobs:
|
||||||
- build-1-19
|
- build-1-23
|
||||||
- build-1-20
|
- build-1-24
|
||||||
- build-1-21
|
- build-1-25
|
||||||
- build-1-22
|
|
||||||
|
|
|
||||||
|
|
@ -2,3 +2,4 @@ dist/
|
||||||
.idea/
|
.idea/
|
||||||
VERSION
|
VERSION
|
||||||
.tmp/
|
.tmp/
|
||||||
|
*.snap
|
||||||
|
|
|
||||||
|
|
@ -8,14 +8,23 @@ builds:
|
||||||
goarch:
|
goarch:
|
||||||
- amd64
|
- amd64
|
||||||
- 386
|
- 386
|
||||||
|
- arm
|
||||||
- arm64
|
- arm64
|
||||||
- s390x
|
- s390x
|
||||||
- ppc64le
|
- ppc64le
|
||||||
|
goarm:
|
||||||
|
- 5
|
||||||
|
- 6
|
||||||
|
- 7
|
||||||
ignore:
|
ignore:
|
||||||
- goos: darwin
|
- goos: darwin
|
||||||
goarch: 386
|
goarch: 386
|
||||||
- goos: windows
|
- goos: windows
|
||||||
goarch: arm64
|
goarch: arm64
|
||||||
|
- goos: darwin
|
||||||
|
goarch: arm
|
||||||
|
- goos: windows
|
||||||
|
goarch: arm
|
||||||
- goos: darwin
|
- goos: darwin
|
||||||
goarch: s390x
|
goarch: s390x
|
||||||
- goos: windows
|
- goos: windows
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
FROM golang:1.18-alpine as builder
|
FROM golang:1.25-alpine AS builder
|
||||||
MAINTAINER Fullstory Engineering
|
LABEL maintainer="Fullstory Engineering"
|
||||||
|
|
||||||
# create non-privileged group and user
|
# create non-privileged group and user
|
||||||
RUN addgroup -S grpcurl && adduser -S grpcurl -G grpcurl
|
RUN addgroup -S grpcurl && adduser -S grpcurl -G grpcurl
|
||||||
|
|
@ -16,7 +16,7 @@ RUN go build -o /grpcurl \
|
||||||
-ldflags "-w -extldflags \"-static\" -X \"main.version=$(cat VERSION)\"" \
|
-ldflags "-w -extldflags \"-static\" -X \"main.version=$(cat VERSION)\"" \
|
||||||
./cmd/grpcurl
|
./cmd/grpcurl
|
||||||
|
|
||||||
FROM alpine:3 as alpine
|
FROM alpine:3 AS alpine
|
||||||
WORKDIR /
|
WORKDIR /
|
||||||
COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ca-certificates.crt
|
COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ca-certificates.crt
|
||||||
COPY --from=builder /etc/passwd /etc/passwd
|
COPY --from=builder /etc/passwd /etc/passwd
|
||||||
|
|
|
||||||
21
Makefile
21
Makefile
|
|
@ -1,11 +1,11 @@
|
||||||
dev_build_version=$(shell git describe --tags --always --dirty)
|
dev_build_version=$(shell git describe --tags --always --dirty)
|
||||||
|
|
||||||
export PATH := $(shell pwd)/.tmp/protoc/bin:$(PATH)
|
export PATH := $(shell pwd)/.tmp/protoc/bin:$(PATH)
|
||||||
|
|
||||||
export PROTOC_VERSION := 22.0
|
export PROTOC_VERSION := 22.0
|
||||||
|
|
||||||
# Disable CGO for improved compatibility across distros
|
# Disable CGO for improved compatibility across distros
|
||||||
export CGO_ENABLED=0
|
export CGO_ENABLED=0
|
||||||
|
export GOFLAGS=-trimpath
|
||||||
|
export GOWORK=off
|
||||||
|
|
||||||
# TODO: run golint and errcheck, but only to catch *new* violations and
|
# TODO: run golint and errcheck, but only to catch *new* violations and
|
||||||
# decide whether to change code or not (e.g. we need to be able to whitelist
|
# decide whether to change code or not (e.g. we need to be able to whitelist
|
||||||
|
|
@ -44,13 +44,15 @@ docker:
|
||||||
generate: .tmp/protoc/bin/protoc
|
generate: .tmp/protoc/bin/protoc
|
||||||
@go install google.golang.org/protobuf/cmd/protoc-gen-go@a709e31e5d12
|
@go install google.golang.org/protobuf/cmd/protoc-gen-go@a709e31e5d12
|
||||||
@go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@v1.1.0
|
@go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@v1.1.0
|
||||||
|
@go install github.com/jhump/protoreflect/desc/sourceinfo/cmd/protoc-gen-gosrcinfo@v1.14.1
|
||||||
go generate ./...
|
go generate ./...
|
||||||
|
go mod tidy
|
||||||
|
|
||||||
.PHONY: checkgenerate
|
.PHONY: checkgenerate
|
||||||
checkgenerate: generate
|
checkgenerate: generate
|
||||||
git status --porcelain
|
git status --porcelain -- '**/*.go'
|
||||||
@if [ -n "$$(git status --porcelain)" ]; then \
|
@if [ -n "$$(git status --porcelain -- '**/*.go')" ]; then \
|
||||||
git diff; \
|
git diff -- '**/*.go'; \
|
||||||
exit 1; \
|
exit 1; \
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
@ -67,8 +69,8 @@ vet:
|
||||||
|
|
||||||
.PHONY: staticcheck
|
.PHONY: staticcheck
|
||||||
staticcheck:
|
staticcheck:
|
||||||
@go install honnef.co/go/tools/cmd/staticcheck@v0.4.3
|
@go install honnef.co/go/tools/cmd/staticcheck@2025.1.1
|
||||||
staticcheck ./...
|
staticcheck -checks "inherit,-SA1019" ./...
|
||||||
|
|
||||||
.PHONY: ineffassign
|
.PHONY: ineffassign
|
||||||
ineffassign:
|
ineffassign:
|
||||||
|
|
@ -77,7 +79,7 @@ ineffassign:
|
||||||
|
|
||||||
.PHONY: predeclared
|
.PHONY: predeclared
|
||||||
predeclared:
|
predeclared:
|
||||||
@go install github.com/nishanths/predeclared@5f2f810c9ae6
|
@go install github.com/nishanths/predeclared@51e8c974458a0f93dc03fe356f91ae1a6d791e6f
|
||||||
predeclared ./...
|
predeclared ./...
|
||||||
|
|
||||||
# Intentionally omitted from CI, but target here for ad-hoc reports.
|
# Intentionally omitted from CI, but target here for ad-hoc reports.
|
||||||
|
|
@ -93,8 +95,7 @@ errcheck:
|
||||||
errcheck ./...
|
errcheck ./...
|
||||||
|
|
||||||
.PHONY: test
|
.PHONY: test
|
||||||
test:
|
test: deps
|
||||||
# The race detector requires CGO: https://github.com/golang/go/issues/6508
|
|
||||||
CGO_ENABLED=1 go test -race ./...
|
CGO_ENABLED=1 go test -race ./...
|
||||||
|
|
||||||
.tmp/protoc/bin/protoc: ./Makefile ./download_protoc.sh
|
.tmp/protoc/bin/protoc: ./Makefile ./download_protoc.sh
|
||||||
|
|
|
||||||
21
README.md
21
README.md
|
|
@ -1,6 +1,7 @@
|
||||||
# gRPCurl
|
# gRPCurl
|
||||||
[](https://circleci.com/gh/fullstorydev/grpcurl/tree/master)
|
[](https://circleci.com/gh/fullstorydev/grpcurl/tree/master)
|
||||||
[](https://goreportcard.com/report/github.com/fullstorydev/grpcurl)
|
[](https://goreportcard.com/report/github.com/fullstorydev/grpcurl)
|
||||||
|
[](https://snapcraft.io/grpcurl)
|
||||||
|
|
||||||
`grpcurl` is a command-line tool that lets you interact with gRPC servers. It's
|
`grpcurl` is a command-line tool that lets you interact with gRPC servers. It's
|
||||||
basically `curl` for gRPC servers.
|
basically `curl` for gRPC servers.
|
||||||
|
|
@ -79,6 +80,12 @@ of environments, including Windows and myriad Linux distributions.
|
||||||
You can see more details and the full list of other packages for `grpcurl` at _repology.org_:
|
You can see more details and the full list of other packages for `grpcurl` at _repology.org_:
|
||||||
https://repology.org/project/grpcurl/information
|
https://repology.org/project/grpcurl/information
|
||||||
|
|
||||||
|
### Snap
|
||||||
|
|
||||||
|
You can install `grpcurl` using the snap package:
|
||||||
|
|
||||||
|
`snap install grpcurl`
|
||||||
|
|
||||||
### From Source
|
### From Source
|
||||||
If you already have the [Go SDK](https://golang.org/doc/install) installed, you can use the `go`
|
If you already have the [Go SDK](https://golang.org/doc/install) installed, you can use the `go`
|
||||||
tool to install `grpcurl`:
|
tool to install `grpcurl`:
|
||||||
|
|
@ -145,6 +152,13 @@ grpcurl -d @ grpc.server.com:443 my.custom.server.Service/Method <<EOM
|
||||||
}
|
}
|
||||||
EOM
|
EOM
|
||||||
```
|
```
|
||||||
|
### Adding Headers/Metadata to Request
|
||||||
|
Adding of headers / metadata to a rpc request is possible via the `-H name:value` command line option. Multiple headers can be added in a similar fashion.
|
||||||
|
Example :
|
||||||
|
```shell
|
||||||
|
grpcurl -H header1:value1 -H header2:value2 -d '{"id": 1234, "tags": ["foo","bar"]}' grpc.server.com:443 my.custom.server.Service/Method
|
||||||
|
```
|
||||||
|
For more usage guide, check out the help docs via `grpcurl -help`
|
||||||
|
|
||||||
### Listing Services
|
### Listing Services
|
||||||
To list all services exposed by a server, use the "list" verb. When using `.proto` source
|
To list all services exposed by a server, use the "list" verb. When using `.proto` source
|
||||||
|
|
@ -159,6 +173,13 @@ grpcurl -protoset my-protos.bin list
|
||||||
|
|
||||||
# Using proto sources
|
# Using proto sources
|
||||||
grpcurl -import-path ../protos -proto my-stuff.proto list
|
grpcurl -import-path ../protos -proto my-stuff.proto list
|
||||||
|
|
||||||
|
# Export proto files (use -proto-out-dir to specify the output directory)
|
||||||
|
grpcurl -plaintext -proto-out-dir "out_protos" "localhost:8787" describe my.custom.server.Service
|
||||||
|
|
||||||
|
# Export protoset file (use -protoset-out to specify the output file)
|
||||||
|
grpcurl -plaintext -protoset-out "out.protoset" "localhost:8787" describe my.custom.server.Service
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
The "list" verb also lets you see all methods in a particular service:
|
The "list" verb also lets you see all methods in a particular service:
|
||||||
|
|
|
||||||
|
|
@ -8,13 +8,14 @@ import (
|
||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
"math"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/jhump/protoreflect/desc"
|
"github.com/jhump/protoreflect/desc" //lint:ignore SA1019 required to use APIs in other grpcurl package
|
||||||
"github.com/jhump/protoreflect/grpcreflect"
|
"github.com/jhump/protoreflect/grpcreflect"
|
||||||
"google.golang.org/grpc"
|
"google.golang.org/grpc"
|
||||||
"google.golang.org/grpc/codes"
|
"google.golang.org/grpc/codes"
|
||||||
|
|
@ -33,9 +34,9 @@ import (
|
||||||
"github.com/fullstorydev/grpcurl"
|
"github.com/fullstorydev/grpcurl"
|
||||||
)
|
)
|
||||||
|
|
||||||
// To avoid confusion between program error codes and the gRPC resonse
|
// To avoid confusion between program error codes and the gRPC response
|
||||||
// status codes 'Cancelled' and 'Unknown', 1 and 2 respectively,
|
// status codes 'Cancelled' and 'Unknown', 1 and 2 respectively,
|
||||||
// the response status codes emitted use an offest of 64
|
// the response status codes emitted use an offset of 64
|
||||||
const statusCodeOffset = 64
|
const statusCodeOffset = 64
|
||||||
|
|
||||||
const noVersion = "dev build <no version set>"
|
const noVersion = "dev build <no version set>"
|
||||||
|
|
@ -151,6 +152,14 @@ var (
|
||||||
file if this option is given. When invoking an RPC and this option is
|
file if this option is given. When invoking an RPC and this option is
|
||||||
given, the method being invoked and its transitive dependencies will be
|
given, the method being invoked and its transitive dependencies will be
|
||||||
included in the output file.`))
|
included in the output file.`))
|
||||||
|
protoOut = flags.String("proto-out-dir", "", prettify(`
|
||||||
|
The name of a directory where the generated .proto files will be written.
|
||||||
|
With the list and describe verbs, the listed or described elements and
|
||||||
|
their transitive dependencies will be written as .proto files in the
|
||||||
|
specified directory if this option is given. When invoking an RPC and
|
||||||
|
this option is given, the method being invoked and its transitive
|
||||||
|
dependencies will be included in the generated .proto files in the
|
||||||
|
output directory.`))
|
||||||
msgTemplate = flags.Bool("msg-template", false, prettify(`
|
msgTemplate = flags.Bool("msg-template", false, prettify(`
|
||||||
When describing messages, show a template of input data.`))
|
When describing messages, show a template of input data.`))
|
||||||
verbose = flags.Bool("v", false, prettify(`
|
verbose = flags.Bool("v", false, prettify(`
|
||||||
|
|
@ -449,7 +458,7 @@ func main() {
|
||||||
|
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
if *maxTime > 0 {
|
if *maxTime > 0 {
|
||||||
timeout := time.Duration(*maxTime * float64(time.Second))
|
timeout := floatSecondsToDuration(*maxTime)
|
||||||
var cancel context.CancelFunc
|
var cancel context.CancelFunc
|
||||||
ctx, cancel = context.WithTimeout(ctx, timeout)
|
ctx, cancel = context.WithTimeout(ctx, timeout)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
@ -460,13 +469,13 @@ func main() {
|
||||||
defer dialTiming.Done()
|
defer dialTiming.Done()
|
||||||
dialTime := 10 * time.Second
|
dialTime := 10 * time.Second
|
||||||
if *connectTimeout > 0 {
|
if *connectTimeout > 0 {
|
||||||
dialTime = time.Duration(*connectTimeout * float64(time.Second))
|
dialTime = floatSecondsToDuration(*connectTimeout)
|
||||||
}
|
}
|
||||||
ctx, cancel := context.WithTimeout(ctx, dialTime)
|
ctx, cancel := context.WithTimeout(ctx, dialTime)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
var opts []grpc.DialOption
|
var opts []grpc.DialOption
|
||||||
if *keepaliveTime > 0 {
|
if *keepaliveTime > 0 {
|
||||||
timeout := time.Duration(*keepaliveTime * float64(time.Second))
|
timeout := floatSecondsToDuration(*keepaliveTime)
|
||||||
opts = append(opts, grpc.WithKeepaliveParams(keepalive.ClientParameters{
|
opts = append(opts, grpc.WithKeepaliveParams(keepalive.ClientParameters{
|
||||||
Time: timeout,
|
Time: timeout,
|
||||||
Timeout: timeout,
|
Timeout: timeout,
|
||||||
|
|
@ -475,12 +484,12 @@ func main() {
|
||||||
if *maxMsgSz > 0 {
|
if *maxMsgSz > 0 {
|
||||||
opts = append(opts, grpc.WithDefaultCallOptions(grpc.MaxCallRecvMsgSize(*maxMsgSz)))
|
opts = append(opts, grpc.WithDefaultCallOptions(grpc.MaxCallRecvMsgSize(*maxMsgSz)))
|
||||||
}
|
}
|
||||||
network := "tcp"
|
if isUnixSocket != nil && isUnixSocket() && !strings.HasPrefix(target, "unix://") {
|
||||||
if isUnixSocket != nil && isUnixSocket() {
|
// prepend unix:// to the address if it's not already there
|
||||||
network = "unix"
|
// this is to maintain backwards compatibility because the custom dialer is replaced by
|
||||||
if *authority == "" {
|
// the default dialer in grpc-go.
|
||||||
*authority = "localhost"
|
// https://github.com/fullstorydev/grpcurl/pull/480
|
||||||
}
|
target = "unix://" + target
|
||||||
}
|
}
|
||||||
var creds credentials.TransportCredentials
|
var creds credentials.TransportCredentials
|
||||||
if *plaintext {
|
if *plaintext {
|
||||||
|
|
@ -548,7 +557,7 @@ func main() {
|
||||||
|
|
||||||
blockingDialTiming := dialTiming.Child("BlockingDial")
|
blockingDialTiming := dialTiming.Child("BlockingDial")
|
||||||
defer blockingDialTiming.Done()
|
defer blockingDialTiming.Done()
|
||||||
cc, err := grpcurl.BlockingDial(ctx, network, target, creds, opts...)
|
cc, err := grpcurl.BlockingDial(ctx, "", target, creds, opts...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fail(err, "Failed to dial target host %q", target)
|
fail(err, "Failed to dial target host %q", target)
|
||||||
}
|
}
|
||||||
|
|
@ -645,6 +654,9 @@ func main() {
|
||||||
if err := writeProtoset(descSource, svcs...); err != nil {
|
if err := writeProtoset(descSource, svcs...); err != nil {
|
||||||
fail(err, "Failed to write protoset to %s", *protosetOut)
|
fail(err, "Failed to write protoset to %s", *protosetOut)
|
||||||
}
|
}
|
||||||
|
if err := writeProtos(descSource, svcs...); err != nil {
|
||||||
|
fail(err, "Failed to write protos to %s", *protoOut)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
methods, err := grpcurl.ListMethods(descSource, symbol)
|
methods, err := grpcurl.ListMethods(descSource, symbol)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -660,6 +672,9 @@ func main() {
|
||||||
if err := writeProtoset(descSource, symbol); err != nil {
|
if err := writeProtoset(descSource, symbol); err != nil {
|
||||||
fail(err, "Failed to write protoset to %s", *protosetOut)
|
fail(err, "Failed to write protoset to %s", *protosetOut)
|
||||||
}
|
}
|
||||||
|
if err := writeProtos(descSource, symbol); err != nil {
|
||||||
|
fail(err, "Failed to write protos to %s", *protoOut)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if describe {
|
} else if describe {
|
||||||
|
|
@ -764,6 +779,9 @@ func main() {
|
||||||
if err := writeProtoset(descSource, symbols...); err != nil {
|
if err := writeProtoset(descSource, symbols...); err != nil {
|
||||||
fail(err, "Failed to write protoset to %s", *protosetOut)
|
fail(err, "Failed to write protoset to %s", *protosetOut)
|
||||||
}
|
}
|
||||||
|
if err := writeProtos(descSource, symbol); err != nil {
|
||||||
|
fail(err, "Failed to write protos to %s", *protoOut)
|
||||||
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// Invoke an RPC
|
// Invoke an RPC
|
||||||
|
|
@ -830,11 +848,11 @@ func main() {
|
||||||
}
|
}
|
||||||
|
|
||||||
func dumpTiming(td *timingData, lvl int) {
|
func dumpTiming(td *timingData, lvl int) {
|
||||||
ind := ""
|
var ind strings.Builder
|
||||||
for x := 0; x < lvl; x++ {
|
for x := 0; x < lvl; x++ {
|
||||||
ind += " "
|
ind.WriteString(" ")
|
||||||
}
|
}
|
||||||
fmt.Printf("%s%s: %s\n", ind, td.Title, td.Value)
|
fmt.Printf("%s%s: %s\n", ind.String(), td.Title, td.Value)
|
||||||
for _, sd := range td.Sub {
|
for _, sd := range td.Sub {
|
||||||
dumpTiming(sd, lvl+1)
|
dumpTiming(sd, lvl+1)
|
||||||
}
|
}
|
||||||
|
|
@ -923,6 +941,13 @@ func writeProtoset(descSource grpcurl.DescriptorSource, symbols ...string) error
|
||||||
return grpcurl.WriteProtoset(f, descSource, symbols...)
|
return grpcurl.WriteProtoset(f, descSource, symbols...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func writeProtos(descSource grpcurl.DescriptorSource, symbols ...string) error {
|
||||||
|
if *protoOut == "" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return grpcurl.WriteProtoFiles(*protoOut, descSource, symbols...)
|
||||||
|
}
|
||||||
|
|
||||||
type optionalBoolFlag struct {
|
type optionalBoolFlag struct {
|
||||||
set, val bool
|
set, val bool
|
||||||
}
|
}
|
||||||
|
|
@ -947,3 +972,12 @@ func (f *optionalBoolFlag) Set(s string) error {
|
||||||
func (f *optionalBoolFlag) IsBoolFlag() bool {
|
func (f *optionalBoolFlag) IsBoolFlag() bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func floatSecondsToDuration(seconds float64) time.Duration {
|
||||||
|
durationFloat := seconds * float64(time.Second)
|
||||||
|
if durationFloat > math.MaxInt64 {
|
||||||
|
// Avoid overflow
|
||||||
|
return math.MaxInt64
|
||||||
|
}
|
||||||
|
return time.Duration(durationFloat)
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,12 +6,14 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
|
"path/filepath"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/golang/protobuf/proto" //lint:ignore SA1019 we have to import this because it appears in exported API
|
"github.com/golang/protobuf/proto" //lint:ignore SA1019 we have to import these because some of their types appear in exported API
|
||||||
"github.com/jhump/protoreflect/desc"
|
"github.com/jhump/protoreflect/desc" //lint:ignore SA1019 same as above
|
||||||
"github.com/jhump/protoreflect/desc/protoparse"
|
"github.com/jhump/protoreflect/desc/protoparse" //lint:ignore SA1019 same as above
|
||||||
"github.com/jhump/protoreflect/dynamic"
|
"github.com/jhump/protoreflect/desc/protoprint"
|
||||||
|
"github.com/jhump/protoreflect/dynamic" //lint:ignore SA1019 same as above
|
||||||
"github.com/jhump/protoreflect/grpcreflect"
|
"github.com/jhump/protoreflect/grpcreflect"
|
||||||
"google.golang.org/grpc/codes"
|
"google.golang.org/grpc/codes"
|
||||||
"google.golang.org/grpc/status"
|
"google.golang.org/grpc/status"
|
||||||
|
|
@ -258,19 +260,9 @@ func reflectionSupport(err error) error {
|
||||||
// given output. The output will include descriptors for all files in which the
|
// given output. The output will include descriptors for all files in which the
|
||||||
// symbols are defined as well as their transitive dependencies.
|
// symbols are defined as well as their transitive dependencies.
|
||||||
func WriteProtoset(out io.Writer, descSource DescriptorSource, symbols ...string) error {
|
func WriteProtoset(out io.Writer, descSource DescriptorSource, symbols ...string) error {
|
||||||
// compute set of file descriptors
|
filenames, fds, err := getFileDescriptors(symbols, descSource)
|
||||||
filenames := make([]string, 0, len(symbols))
|
if err != nil {
|
||||||
fds := make(map[string]*desc.FileDescriptor, len(symbols))
|
return err
|
||||||
for _, sym := range symbols {
|
|
||||||
d, err := descSource.FindSymbol(sym)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("failed to find descriptor for %q: %v", sym, err)
|
|
||||||
}
|
|
||||||
fd := d.GetFile()
|
|
||||||
if _, ok := fds[fd.GetName()]; !ok {
|
|
||||||
fds[fd.GetName()] = fd
|
|
||||||
filenames = append(filenames, fd.GetName())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// now expand that to include transitive dependencies in topologically sorted
|
// now expand that to include transitive dependencies in topologically sorted
|
||||||
// order (such that file always appears after its dependencies)
|
// order (such that file always appears after its dependencies)
|
||||||
|
|
@ -302,3 +294,76 @@ func addFilesToSet(allFiles []*descriptorpb.FileDescriptorProto, expanded map[st
|
||||||
}
|
}
|
||||||
return append(allFiles, fd.AsFileDescriptorProto())
|
return append(allFiles, fd.AsFileDescriptorProto())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// WriteProtoFiles will use the given descriptor source to resolve all the given
|
||||||
|
// symbols and write proto files with their definitions to the given output directory.
|
||||||
|
func WriteProtoFiles(outProtoDirPath string, descSource DescriptorSource, symbols ...string) error {
|
||||||
|
filenames, fds, err := getFileDescriptors(symbols, descSource)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// now expand that to include transitive dependencies in topologically sorted
|
||||||
|
// order (such that file always appears after its dependencies)
|
||||||
|
expandedFiles := make(map[string]struct{}, len(fds))
|
||||||
|
allFileDescriptors := make([]*desc.FileDescriptor, 0, len(fds))
|
||||||
|
for _, filename := range filenames {
|
||||||
|
allFileDescriptors = addFilesToFileDescriptorList(allFileDescriptors, expandedFiles, fds[filename])
|
||||||
|
}
|
||||||
|
pr := protoprint.Printer{}
|
||||||
|
// now we can serialize to files
|
||||||
|
for i := range allFileDescriptors {
|
||||||
|
if err := writeProtoFile(outProtoDirPath, allFileDescriptors[i], &pr); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func writeProtoFile(outProtoDirPath string, fd *desc.FileDescriptor, pr *protoprint.Printer) error {
|
||||||
|
outFile := filepath.Join(outProtoDirPath, fd.GetFullyQualifiedName())
|
||||||
|
outDir := filepath.Dir(outFile)
|
||||||
|
if err := os.MkdirAll(outDir, 0777); err != nil {
|
||||||
|
return fmt.Errorf("failed to create directory %q: %w", outDir, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
f, err := os.Create(outFile)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to create proto file %q: %w", outFile, err)
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
if err := pr.PrintProtoFile(fd, f); err != nil {
|
||||||
|
return fmt.Errorf("failed to write proto file %q: %w", outFile, err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func getFileDescriptors(symbols []string, descSource DescriptorSource) ([]string, map[string]*desc.FileDescriptor, error) {
|
||||||
|
// compute set of file descriptors
|
||||||
|
filenames := make([]string, 0, len(symbols))
|
||||||
|
fds := make(map[string]*desc.FileDescriptor, len(symbols))
|
||||||
|
for _, sym := range symbols {
|
||||||
|
d, err := descSource.FindSymbol(sym)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, fmt.Errorf("failed to find descriptor for %q: %v", sym, err)
|
||||||
|
}
|
||||||
|
fd := d.GetFile()
|
||||||
|
if _, ok := fds[fd.GetName()]; !ok {
|
||||||
|
fds[fd.GetName()] = fd
|
||||||
|
filenames = append(filenames, fd.GetName())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return filenames, fds, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func addFilesToFileDescriptorList(allFiles []*desc.FileDescriptor, expanded map[string]struct{}, fd *desc.FileDescriptor) []*desc.FileDescriptor {
|
||||||
|
if _, ok := expanded[fd.GetName()]; ok {
|
||||||
|
// already seen this one
|
||||||
|
return allFiles
|
||||||
|
}
|
||||||
|
expanded[fd.GetName()] = struct{}{}
|
||||||
|
// add all dependencies first
|
||||||
|
for _, dep := range fd.GetDependencies() {
|
||||||
|
allFiles = addFilesToFileDescriptorList(allFiles, expanded, dep)
|
||||||
|
}
|
||||||
|
return append(allFiles, fd)
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,10 +11,10 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/golang/protobuf/jsonpb" //lint:ignore SA1019 we have to import this because it appears in exported API
|
"github.com/golang/protobuf/jsonpb" //lint:ignore SA1019 we have to import these because some of their types appear in exported API
|
||||||
"github.com/golang/protobuf/proto" //lint:ignore SA1019 we have to import this because it appears in exported API
|
"github.com/golang/protobuf/proto" //lint:ignore SA1019 same as above
|
||||||
"github.com/jhump/protoreflect/desc"
|
"github.com/jhump/protoreflect/desc" //lint:ignore SA1019 same as above
|
||||||
"github.com/jhump/protoreflect/dynamic"
|
"github.com/jhump/protoreflect/dynamic" //lint:ignore SA1019 same as above
|
||||||
"google.golang.org/grpc/codes"
|
"google.golang.org/grpc/codes"
|
||||||
"google.golang.org/grpc/metadata"
|
"google.golang.org/grpc/metadata"
|
||||||
"google.golang.org/grpc/status"
|
"google.golang.org/grpc/status"
|
||||||
|
|
|
||||||
|
|
@ -7,9 +7,9 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/golang/protobuf/jsonpb" //lint:ignore SA1019 we have to import this because it appears in exported API
|
"github.com/golang/protobuf/jsonpb" //lint:ignore SA1019 we have to import these because some of their types appear in exported API
|
||||||
"github.com/golang/protobuf/proto" //lint:ignore SA1019 we have to import this because it appears in exported API
|
"github.com/golang/protobuf/proto" //lint:ignore SA1019 same as above
|
||||||
"github.com/jhump/protoreflect/desc"
|
"github.com/jhump/protoreflect/desc" //lint:ignore SA1019 same as above
|
||||||
"google.golang.org/grpc/metadata"
|
"google.golang.org/grpc/metadata"
|
||||||
"google.golang.org/protobuf/types/known/structpb"
|
"google.golang.org/protobuf/types/known/structpb"
|
||||||
)
|
)
|
||||||
|
|
|
||||||
43
go.mod
43
go.mod
|
|
@ -1,31 +1,32 @@
|
||||||
module github.com/fullstorydev/grpcurl
|
module github.com/fullstorydev/grpcurl
|
||||||
|
|
||||||
go 1.19
|
go 1.24.0
|
||||||
|
|
||||||
|
toolchain go1.24.1
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/golang/protobuf v1.5.4
|
github.com/golang/protobuf v1.5.4
|
||||||
github.com/jhump/protoreflect v1.16.0
|
github.com/jhump/protoreflect v1.18.0
|
||||||
google.golang.org/grpc v1.61.0
|
google.golang.org/grpc v1.66.2
|
||||||
google.golang.org/protobuf v1.33.1-0.20240408130810-98873a205002
|
google.golang.org/protobuf v1.36.11
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
cloud.google.com/go/compute v1.23.3 // indirect
|
cel.dev/expr v0.15.0 // indirect
|
||||||
cloud.google.com/go/compute/metadata v0.2.3 // indirect
|
cloud.google.com/go/compute/metadata v0.3.0 // indirect
|
||||||
github.com/bufbuild/protocompile v0.10.0 // indirect
|
|
||||||
github.com/census-instrumentation/opencensus-proto v0.4.1 // indirect
|
github.com/census-instrumentation/opencensus-proto v0.4.1 // indirect
|
||||||
github.com/cespare/xxhash/v2 v2.2.0 // indirect
|
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
||||||
github.com/cncf/udpa/go v0.0.0-20220112060539-c52dc94e7fbe // indirect
|
github.com/cncf/xds/go v0.0.0-20240423153145-555b57ec207b // indirect
|
||||||
github.com/cncf/xds/go v0.0.0-20231109132714-523115ebc101 // indirect
|
github.com/envoyproxy/go-control-plane v0.12.1-0.20240621013728-1eb8caab5155 // indirect
|
||||||
github.com/envoyproxy/go-control-plane v0.11.1 // indirect
|
github.com/envoyproxy/protoc-gen-validate v1.0.4 // indirect
|
||||||
github.com/envoyproxy/protoc-gen-validate v1.0.2 // indirect
|
github.com/jhump/protoreflect/v2 v2.0.0-beta.1 // indirect
|
||||||
golang.org/x/net v0.22.0 // indirect
|
github.com/petermattis/goid v0.0.0-20260113132338-7c7de50cc741 // indirect
|
||||||
golang.org/x/oauth2 v0.14.0 // indirect
|
github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 // indirect
|
||||||
golang.org/x/sync v0.6.0 // indirect
|
golang.org/x/net v0.38.0 // indirect
|
||||||
golang.org/x/sys v0.18.0 // indirect
|
golang.org/x/oauth2 v0.27.0 // indirect
|
||||||
golang.org/x/text v0.14.0 // indirect
|
golang.org/x/sync v0.12.0 // indirect
|
||||||
google.golang.org/appengine v1.6.8 // indirect
|
golang.org/x/sys v0.31.0 // indirect
|
||||||
google.golang.org/genproto v0.0.0-20231106174013-bbf56f31fb17 // indirect
|
golang.org/x/text v0.23.0 // indirect
|
||||||
google.golang.org/genproto/googleapis/api v0.0.0-20231106174013-bbf56f31fb17 // indirect
|
google.golang.org/genproto/googleapis/api v0.0.0-20240604185151-ef581f913117 // indirect
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20231106174013-bbf56f31fb17 // indirect
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20240604185151-ef581f913117 // indirect
|
||||||
)
|
)
|
||||||
|
|
|
||||||
158
go.sum
158
go.sum
|
|
@ -1,118 +1,56 @@
|
||||||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
cel.dev/expr v0.15.0 h1:O1jzfJCQBfL5BFoYktaxwIhuttaQPsVWerH9/EEKx0w=
|
||||||
cloud.google.com/go/compute v1.23.3 h1:6sVlXXBmbd7jNX0Ipq0trII3e4n1/MsADLK6a+aiVlk=
|
cel.dev/expr v0.15.0/go.mod h1:TRSuuV7DlVCE/uwv5QbAiW/v8l5O8C4eEPHeu7gf7Sg=
|
||||||
cloud.google.com/go/compute v1.23.3/go.mod h1:VCgBUoMnIVIR0CscqQiPJLAG25E3ZRZMzcFZeQ+h8CI=
|
cloud.google.com/go/compute/metadata v0.3.0 h1:Tz+eQXMEqDIKRsmY3cHTL6FVaynIjX2QxYC4trgAKZc=
|
||||||
cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY=
|
cloud.google.com/go/compute/metadata v0.3.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k=
|
||||||
cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA=
|
github.com/bufbuild/protocompile v0.14.1 h1:iA73zAf/fyljNjQKwYzUHD6AD4R8KMasmwa/FBatYVw=
|
||||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
github.com/bufbuild/protocompile v0.14.1/go.mod h1:ppVdAIhbr2H8asPk6k4pY7t9zB1OU5DoEw9xY/FUi1c=
|
||||||
github.com/bufbuild/protocompile v0.10.0 h1:+jW/wnLMLxaCEG8AX9lD0bQ5v9h1RUiMKOBOT5ll9dM=
|
|
||||||
github.com/bufbuild/protocompile v0.10.0/go.mod h1:G9qQIQo0xZ6Uyj6CMNz0saGmx2so+KONo8/KrELABiY=
|
|
||||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
|
||||||
github.com/census-instrumentation/opencensus-proto v0.4.1 h1:iKLQ0xPNFxR/2hzXZMrBo8f1j86j5WHzznCCQxV/b8g=
|
github.com/census-instrumentation/opencensus-proto v0.4.1 h1:iKLQ0xPNFxR/2hzXZMrBo8f1j86j5WHzznCCQxV/b8g=
|
||||||
github.com/census-instrumentation/opencensus-proto v0.4.1/go.mod h1:4T9NM4+4Vw91VeyqjLS6ao50K5bOcLKN6Q42XnYaRYw=
|
github.com/census-instrumentation/opencensus-proto v0.4.1/go.mod h1:4T9NM4+4Vw91VeyqjLS6ao50K5bOcLKN6Q42XnYaRYw=
|
||||||
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
|
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
|
||||||
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
github.com/cncf/xds/go v0.0.0-20240423153145-555b57ec207b h1:ga8SEFjZ60pxLcmhnThWgvH2wg8376yUJmPhEH4H3kw=
|
||||||
github.com/cncf/udpa/go v0.0.0-20220112060539-c52dc94e7fbe h1:QQ3GSy+MqSHxm/d8nCtnAiZdYFd45cYZPs8vOOIYKfk=
|
github.com/cncf/xds/go v0.0.0-20240423153145-555b57ec207b/go.mod h1:W+zGtBO5Y1IgJhy4+A9GOqVhqLpfZi+vwmdNXUehLA8=
|
||||||
github.com/cncf/udpa/go v0.0.0-20220112060539-c52dc94e7fbe/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI=
|
|
||||||
github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
|
||||||
github.com/cncf/xds/go v0.0.0-20231109132714-523115ebc101 h1:7To3pQ+pZo0i3dsWEbinPNFs5gPSBOsJtx3wTT94VBY=
|
|
||||||
github.com/cncf/xds/go v0.0.0-20231109132714-523115ebc101/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
|
||||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/envoyproxy/go-control-plane v0.11.1 h1:wSUXTlLfiAQRWs2F+p+EKOY9rUyis1MyGqJ2DIk5HpM=
|
github.com/envoyproxy/go-control-plane v0.12.1-0.20240621013728-1eb8caab5155 h1:IgJPqnrlY2Mr4pYB6oaMKvFvwJ9H+X6CCY5x1vCTcpc=
|
||||||
github.com/envoyproxy/go-control-plane v0.11.1/go.mod h1:uhMcXKCQMEJHiAb0w+YGefQLaTEw+YhGluxZkrTmD0g=
|
github.com/envoyproxy/go-control-plane v0.12.1-0.20240621013728-1eb8caab5155/go.mod h1:5Wkq+JduFtdAXihLmeTJf+tRYIT4KBc2vPXDhwVo1pA=
|
||||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
github.com/envoyproxy/protoc-gen-validate v1.0.4 h1:gVPz/FMfvh57HdSJQyvBtF00j8JU4zdyUgIUNhlgg0A=
|
||||||
github.com/envoyproxy/protoc-gen-validate v1.0.2 h1:QkIBuU5k+x7/QXPvPPnWXWlCdaBFApVqftFV6k087DA=
|
github.com/envoyproxy/protoc-gen-validate v1.0.4/go.mod h1:qys6tmnRsYrQqIhm2bvKZH4Blx/1gTIZ2UKVY1M+Yew=
|
||||||
github.com/envoyproxy/protoc-gen-validate v1.0.2/go.mod h1:GpiZQP3dDbg4JouG/NNS7QWXpgx6x8QiMKdmN72jogE=
|
|
||||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
|
||||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
|
||||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
|
||||||
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
|
||||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
|
||||||
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
|
||||||
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
|
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
|
||||||
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
|
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
|
||||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
|
||||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
|
||||||
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||||
github.com/google/uuid v1.4.0 h1:MtMxsa51/r9yyhkyLsVeVt0B+BGQZzpQiTQ4eHZ8bc4=
|
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
github.com/jhump/protoreflect v1.16.0 h1:54fZg+49widqXYQ0b+usAFHbMkBGR4PpXrsHc8+TBDg=
|
github.com/jhump/protoreflect v1.18.0 h1:TOz0MSR/0JOZ5kECB/0ufGnC2jdsgZ123Rd/k4Z5/2w=
|
||||||
github.com/jhump/protoreflect v1.16.0/go.mod h1:oYPd7nPvcBw/5wlDfm/AVmU9zH9BgqGCI469pGxfj/8=
|
github.com/jhump/protoreflect v1.18.0/go.mod h1:ezWcltJIVF4zYdIFM+D/sHV4Oh5LNU08ORzCGfwvTz8=
|
||||||
|
github.com/jhump/protoreflect/v2 v2.0.0-beta.1 h1:Dw1rslK/VotaUGYsv53XVWITr+5RCPXfvvlGrM/+B6w=
|
||||||
|
github.com/jhump/protoreflect/v2 v2.0.0-beta.1/go.mod h1:D9LBEowZyv8/iSu97FU2zmXG3JxVTmNw21mu63niFzU=
|
||||||
|
github.com/petermattis/goid v0.0.0-20260113132338-7c7de50cc741 h1:KPpdlQLZcHfTMQRi6bFQ7ogNO0ltFT4PmtwTLW4W+14=
|
||||||
|
github.com/petermattis/goid v0.0.0-20260113132338-7c7de50cc741/go.mod h1:pxMtw7cyUw6B2bRH0ZBANSPg+AoSud1I1iyJHI69jH4=
|
||||||
|
github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 h1:GFCKgmp0tecUJ0sJuv4pzYCqS9+RGSn52M3FUwPs+uo=
|
||||||
|
github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10/go.mod h1:t/avpk3KcrXxUnYOhZhMXJlSEyie6gQbtLq5NM3loB8=
|
||||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
||||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
golang.org/x/net v0.38.0 h1:vRMAPTMaeGqVhG5QyLJHqNDwecKTomGeqbnfZyKlBI8=
|
||||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
golang.org/x/net v0.38.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8=
|
||||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
golang.org/x/oauth2 v0.27.0 h1:da9Vo7/tDv5RH/7nZDz1eMGS/q1Vv1N/7FCrBhI9I3M=
|
||||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
golang.org/x/oauth2 v0.27.0/go.mod h1:onh5ek6nERTohokkhCD/y2cV4Do3fxFHFuAejCkRWT8=
|
||||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
golang.org/x/sync v0.12.0 h1:MHc5BpPuC30uJk597Ri8TV3CNZcTLu6B6z4lJy+g6Jw=
|
||||||
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
golang.org/x/sync v0.12.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
|
||||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik=
|
||||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY=
|
||||||
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4=
|
||||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
google.golang.org/genproto/googleapis/api v0.0.0-20240604185151-ef581f913117 h1:+rdxYoE3E5htTEWIe15GlN6IfvbURM//Jt0mmkmm6ZU=
|
||||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
google.golang.org/genproto/googleapis/api v0.0.0-20240604185151-ef581f913117/go.mod h1:OimBR/bc1wPO9iV4NC2bpyjy3VnAwZh5EBPQdtaE5oo=
|
||||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20240604185151-ef581f913117 h1:1GBuWVLM/KMVUv1t1En5Gs+gFZCNd360GGb4sSxtrhU=
|
||||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20240604185151-ef581f913117/go.mod h1:EfXuqaE1J41VCDicxHzUDm+8rk+7ZdXzHV0IhO/I6s0=
|
||||||
golang.org/x/net v0.22.0 h1:9sGLhx7iRIHEiX0oAJ3MRZMUCElJgy7Br1nO+AMN3Tc=
|
google.golang.org/grpc v1.66.2 h1:3QdXkuq3Bkh7w+ywLdLvM56cmGvQHUMZpiCzt6Rqaoo=
|
||||||
golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
|
google.golang.org/grpc v1.66.2/go.mod h1:s3/l6xSSCURdVfAnL+TqCNMyTDAGN6+lZeVxnZR128Y=
|
||||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
|
||||||
golang.org/x/oauth2 v0.14.0 h1:P0Vrf/2538nmC0H+pEQ3MNFRRnVR7RlqyVw+bvm26z0=
|
google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
|
||||||
golang.org/x/oauth2 v0.14.0/go.mod h1:lAtNWgaWfL4cm7j2OV8TxGi9Qb7ECORx8DktCY74OwM=
|
|
||||||
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-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
|
||||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
|
||||||
golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ=
|
|
||||||
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
|
||||||
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-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|
||||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|
||||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|
||||||
golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4=
|
|
||||||
golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
|
||||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
|
||||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
|
||||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
|
||||||
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
|
|
||||||
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
|
|
||||||
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
|
||||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
|
||||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
|
||||||
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
|
||||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
|
||||||
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
|
||||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
|
||||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
|
||||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
|
||||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
|
||||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
|
||||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
|
||||||
google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM=
|
|
||||||
google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds=
|
|
||||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
|
||||||
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
|
||||||
google.golang.org/genproto v0.0.0-20231106174013-bbf56f31fb17 h1:wpZ8pe2x1Q3f2KyT5f8oP/fa9rHAKgFPr/HZdNuS+PQ=
|
|
||||||
google.golang.org/genproto v0.0.0-20231106174013-bbf56f31fb17/go.mod h1:J7XzRzVy1+IPwWHZUzoD0IccYZIrXILAQpc+Qy9CMhY=
|
|
||||||
google.golang.org/genproto/googleapis/api v0.0.0-20231106174013-bbf56f31fb17 h1:JpwMPBpFN3uKhdaekDpiNlImDdkUAyiJ6ez/uxGaUSo=
|
|
||||||
google.golang.org/genproto/googleapis/api v0.0.0-20231106174013-bbf56f31fb17/go.mod h1:0xJLfVdJqpAPl8tDg1ujOCGzx6LFLttXT5NhllGOXY4=
|
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20231106174013-bbf56f31fb17 h1:Jyp0Hsi0bmHXG6k9eATXoYtjd6e2UzZ1SCn/wIupY14=
|
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20231106174013-bbf56f31fb17/go.mod h1:oQ5rr10WTTMvP4A36n8JpR1OrO1BEiV4f78CneXZxkA=
|
|
||||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
|
||||||
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
|
||||||
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
|
|
||||||
google.golang.org/grpc v1.61.0 h1:TOvOcuXn30kRao+gfcvsebNEa5iZIiLkisYEkf7R7o0=
|
|
||||||
google.golang.org/grpc v1.61.0/go.mod h1:VUbo7IFqmF1QtCAstipjG0GIoq49KvMe9+h1jFLBNJs=
|
|
||||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
|
||||||
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
|
||||||
google.golang.org/protobuf v1.33.1-0.20240408130810-98873a205002 h1:V7Da7qt0MkY3noVANIMVBk28nOnijADeOR3i5Hcvpj4=
|
|
||||||
google.golang.org/protobuf v1.33.1-0.20240408130810-98873a205002/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
|
|
||||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
|
||||||
|
|
|
||||||
57
grpcurl.go
57
grpcurl.go
|
|
@ -17,17 +17,19 @@ import (
|
||||||
"net"
|
"net"
|
||||||
"os"
|
"os"
|
||||||
"regexp"
|
"regexp"
|
||||||
|
"slices"
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/golang/protobuf/proto" //lint:ignore SA1019 we have to import this because it appears in exported API
|
"github.com/golang/protobuf/proto" //lint:ignore SA1019 we have to import these because some of their types appear in exported API
|
||||||
"github.com/jhump/protoreflect/desc"
|
"github.com/jhump/protoreflect/desc" //lint:ignore SA1019 same as above
|
||||||
"github.com/jhump/protoreflect/desc/protoprint"
|
"github.com/jhump/protoreflect/desc/protoprint"
|
||||||
"github.com/jhump/protoreflect/dynamic"
|
"github.com/jhump/protoreflect/dynamic" //lint:ignore SA1019 same as above
|
||||||
"google.golang.org/grpc"
|
"google.golang.org/grpc"
|
||||||
"google.golang.org/grpc/credentials"
|
"google.golang.org/grpc/credentials"
|
||||||
"google.golang.org/grpc/credentials/insecure"
|
"google.golang.org/grpc/credentials/insecure"
|
||||||
xdsCredentials "google.golang.org/grpc/credentials/xds"
|
xdsCredentials "google.golang.org/grpc/credentials/xds"
|
||||||
|
_ "google.golang.org/grpc/health" // import grpc/health to enable transparent client side checking
|
||||||
"google.golang.org/grpc/metadata"
|
"google.golang.org/grpc/metadata"
|
||||||
protov2 "google.golang.org/protobuf/proto"
|
protov2 "google.golang.org/protobuf/proto"
|
||||||
"google.golang.org/protobuf/types/descriptorpb"
|
"google.golang.org/protobuf/types/descriptorpb"
|
||||||
|
|
@ -449,11 +451,9 @@ func makeTemplate(md *desc.MessageDescriptor, path []*desc.MessageDescriptor) pr
|
||||||
dm := dynamic.NewMessage(md)
|
dm := dynamic.NewMessage(md)
|
||||||
|
|
||||||
// if the message is a recursive structure, we don't want to blow the stack
|
// if the message is a recursive structure, we don't want to blow the stack
|
||||||
for _, seen := range path {
|
if slices.Contains(path, md) {
|
||||||
if seen == md {
|
// already visited this type; avoid infinite recursion
|
||||||
// already visited this type; avoid infinite recursion
|
return dm
|
||||||
return dm
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
path = append(path, dm.GetMessageDescriptor())
|
path = append(path, dm.GetMessageDescriptor())
|
||||||
|
|
||||||
|
|
@ -608,6 +608,8 @@ func ServerTransportCredentials(cacertFile, serverCertFile, serverKeyFile string
|
||||||
// BlockingDial is a helper method to dial the given address, using optional TLS credentials,
|
// BlockingDial is a helper method to dial the given address, using optional TLS credentials,
|
||||||
// and blocking until the returned connection is ready. If the given credentials are nil, the
|
// and blocking until the returned connection is ready. If the given credentials are nil, the
|
||||||
// connection will be insecure (plain-text).
|
// connection will be insecure (plain-text).
|
||||||
|
// The network parameter should be left empty in most cases when your address is a RFC 3986
|
||||||
|
// compliant URI. The resolver from grpc-go will resolve the correct network type.
|
||||||
func BlockingDial(ctx context.Context, network, address string, creds credentials.TransportCredentials, opts ...grpc.DialOption) (*grpc.ClientConn, error) {
|
func BlockingDial(ctx context.Context, network, address string, creds credentials.TransportCredentials, opts ...grpc.DialOption) (*grpc.ClientConn, error) {
|
||||||
if creds == nil {
|
if creds == nil {
|
||||||
creds = insecure.NewCredentials()
|
creds = insecure.NewCredentials()
|
||||||
|
|
@ -644,19 +646,32 @@ func BlockingDial(ctx context.Context, network, address string, creds credential
|
||||||
writeResult: writeResult,
|
writeResult: writeResult,
|
||||||
}
|
}
|
||||||
|
|
||||||
dialer := func(ctx context.Context, address string) (net.Conn, error) {
|
switch network {
|
||||||
// NB: We *could* handle the TLS handshake ourselves, in the custom
|
case "":
|
||||||
// dialer (instead of customizing both the dialer and the credentials).
|
// no-op, use address as-is
|
||||||
// But that requires using insecure.NewCredentials() dial transport
|
case "tcp":
|
||||||
// option (so that the gRPC library doesn't *also* try to do a
|
if strings.HasPrefix(address, "unix://") {
|
||||||
// handshake). And that would mean that the library would send the
|
return nil, fmt.Errorf("tcp network type cannot use unix address %s", address)
|
||||||
// wrong ":scheme" metaheader to servers: it would send "http" instead
|
|
||||||
// of "https" because it is unaware that TLS is actually in use.
|
|
||||||
conn, err := (&net.Dialer{}).DialContext(ctx, network, address)
|
|
||||||
if err != nil {
|
|
||||||
writeResult(err)
|
|
||||||
}
|
}
|
||||||
return conn, err
|
case "unix":
|
||||||
|
if !strings.HasPrefix(address, "unix://") {
|
||||||
|
// prepend unix:// to the address if it's not already there
|
||||||
|
// this is to maintain backwards compatibility because the custom dialer is replaced by
|
||||||
|
// the default dialer in grpc-go.
|
||||||
|
// https://github.com/fullstorydev/grpcurl/pull/480
|
||||||
|
address = "unix://" + address
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
// custom dialer for other networks
|
||||||
|
dialer := func(ctx context.Context, address string) (net.Conn, error) {
|
||||||
|
conn, err := (&net.Dialer{}).DialContext(ctx, network, address)
|
||||||
|
if err != nil {
|
||||||
|
// capture the error so we can provide a better message
|
||||||
|
writeResult(err)
|
||||||
|
}
|
||||||
|
return conn, err
|
||||||
|
}
|
||||||
|
opts = append([]grpc.DialOption{grpc.WithContextDialer(dialer)}, opts...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Even with grpc.FailOnNonTempDialError, this call will usually timeout in
|
// Even with grpc.FailOnNonTempDialError, this call will usually timeout in
|
||||||
|
|
@ -669,7 +684,7 @@ func BlockingDial(ctx context.Context, network, address string, creds credential
|
||||||
opts = append([]grpc.DialOption{grpc.FailOnNonTempDialError(true)}, opts...)
|
opts = append([]grpc.DialOption{grpc.FailOnNonTempDialError(true)}, opts...)
|
||||||
// But we don't want caller to be able to override these two, so we put
|
// But we don't want caller to be able to override these two, so we put
|
||||||
// them *after* the explicitly provided options.
|
// them *after* the explicitly provided options.
|
||||||
opts = append(opts, grpc.WithBlock(), grpc.WithContextDialer(dialer), grpc.WithTransportCredentials(creds))
|
opts = append(opts, grpc.WithBlock(), grpc.WithTransportCredentials(creds))
|
||||||
|
|
||||||
conn, err := grpc.DialContext(ctx, address, opts...)
|
conn, err := grpc.DialContext(ctx, address, opts...)
|
||||||
var res interface{}
|
var res interface{}
|
||||||
|
|
|
||||||
|
|
@ -12,9 +12,9 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/golang/protobuf/jsonpb" //lint:ignore SA1019 we have to import this because it appears in exported API
|
"github.com/golang/protobuf/jsonpb" //lint:ignore SA1019 we have to import these because some of their types appear in exported API
|
||||||
"github.com/golang/protobuf/proto" //lint:ignore SA1019 we have to import this because it appears in exported API
|
"github.com/golang/protobuf/proto" //lint:ignore SA1019 same as above
|
||||||
"github.com/jhump/protoreflect/desc"
|
"github.com/jhump/protoreflect/desc" //lint:ignore SA1019 same as above
|
||||||
"github.com/jhump/protoreflect/grpcreflect"
|
"github.com/jhump/protoreflect/grpcreflect"
|
||||||
"google.golang.org/grpc"
|
"google.golang.org/grpc"
|
||||||
"google.golang.org/grpc/codes"
|
"google.golang.org/grpc/codes"
|
||||||
|
|
|
||||||
|
|
@ -9,10 +9,10 @@ import (
|
||||||
"sync"
|
"sync"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
|
|
||||||
"github.com/golang/protobuf/jsonpb" //lint:ignore SA1019 we have to import this because it appears in exported API
|
"github.com/golang/protobuf/jsonpb" //lint:ignore SA1019 we have to import these because some of their types appear in exported API
|
||||||
"github.com/golang/protobuf/proto" //lint:ignore SA1019 we have to import this because it appears in exported API
|
"github.com/golang/protobuf/proto" //lint:ignore SA1019 same as above
|
||||||
"github.com/jhump/protoreflect/desc"
|
"github.com/jhump/protoreflect/desc" //lint:ignore SA1019 same as above
|
||||||
"github.com/jhump/protoreflect/dynamic"
|
"github.com/jhump/protoreflect/dynamic" //lint:ignore SA1019 same as above
|
||||||
"github.com/jhump/protoreflect/dynamic/grpcdynamic"
|
"github.com/jhump/protoreflect/dynamic/grpcdynamic"
|
||||||
"github.com/jhump/protoreflect/grpcreflect"
|
"github.com/jhump/protoreflect/grpcreflect"
|
||||||
"google.golang.org/grpc"
|
"google.golang.org/grpc"
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,23 @@
|
||||||
|
# packing and releasing
|
||||||
|
To pack the current branch to a snap package:
|
||||||
|
|
||||||
|
`snapcraft pack`
|
||||||
|
|
||||||
|
To install the package locally:
|
||||||
|
|
||||||
|
`snap install ./grpcurl_v[version tag]_amd64.snap --devmode`
|
||||||
|
|
||||||
|
To upload the snap to the edge channel:
|
||||||
|
|
||||||
|
`snapcraft upload --release edge ./grpcurl_v[version tag]_amd64.snap`
|
||||||
|
|
||||||
|
(you need to own the package name registration for this!)
|
||||||
|
|
||||||
|
# ownership
|
||||||
|
The snap's current owner is `pietro.pasotti@canonical.com`; who is very happy to support with maintaining the snap distribution and/or transfer its ownership to the developers.
|
||||||
|
|
||||||
|
Please reach out to me for questions regarding the snap; including:
|
||||||
|
- adding support for other architectures
|
||||||
|
- automating the release
|
||||||
|
|
||||||
|
Cheers and thanks for the awesome tool!
|
||||||
|
|
@ -0,0 +1,47 @@
|
||||||
|
name: grpcurl
|
||||||
|
base: core24
|
||||||
|
# allow grpcurl part to call craftctl set-version
|
||||||
|
adopt-info: grpcurl
|
||||||
|
summary: grpcurl is a command-line tool that lets you interact with gRPC servers.
|
||||||
|
|
||||||
|
description: |
|
||||||
|
grpcurl is a command-line tool that lets you interact with gRPC servers.
|
||||||
|
It's basically curl for gRPC servers.
|
||||||
|
|
||||||
|
grade: stable
|
||||||
|
confinement: strict
|
||||||
|
license: MIT
|
||||||
|
|
||||||
|
platforms:
|
||||||
|
amd64:
|
||||||
|
build-on:
|
||||||
|
- amd64
|
||||||
|
build-for:
|
||||||
|
- amd64
|
||||||
|
arm64:
|
||||||
|
build-on:
|
||||||
|
- amd64
|
||||||
|
- arm64
|
||||||
|
build-for:
|
||||||
|
- arm64
|
||||||
|
|
||||||
|
apps:
|
||||||
|
grpcurl:
|
||||||
|
command: grpcurl
|
||||||
|
plugs:
|
||||||
|
- network
|
||||||
|
|
||||||
|
parts:
|
||||||
|
grpcurl:
|
||||||
|
plugin: go
|
||||||
|
build-snaps: [go/latest/stable]
|
||||||
|
source: https://github.com/fullstorydev/grpcurl
|
||||||
|
source-type: git
|
||||||
|
override-build: |
|
||||||
|
tag="$(git describe --tags --abbrev=0)"
|
||||||
|
craftctl set version="$tag"
|
||||||
|
|
||||||
|
go build -o $CRAFT_PART_INSTALL/grpcurl ./cmd/grpcurl/grpcurl.go
|
||||||
|
|
||||||
|
# adjust the permissions
|
||||||
|
chmod 0755 $CRAFT_PART_INSTALL/grpcurl
|
||||||
|
|
@ -253,8 +253,12 @@ func TestBrokenTLS_ClientNotTrusted(t *testing.T) {
|
||||||
e.Close()
|
e.Close()
|
||||||
t.Fatal("expecting TLS failure setting up server and client")
|
t.Fatal("expecting TLS failure setting up server and client")
|
||||||
}
|
}
|
||||||
if !strings.Contains(err.Error(), "bad certificate") {
|
// Check for either the old error (Go <=1.24) or the new one (Go 1.25+)
|
||||||
t.Fatalf("expecting TLS certificate error, got: %v", err)
|
// Go 1.24: "bad certificate"
|
||||||
|
// Go 1.25: "handshake failure"
|
||||||
|
errMsg := err.Error()
|
||||||
|
if !strings.Contains(errMsg, "bad certificate") && !strings.Contains(errMsg, "handshake failure") {
|
||||||
|
t.Fatalf("expecting a specific TLS certificate or handshake error, got: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -293,8 +297,12 @@ func TestBrokenTLS_RequireClientCertButNonePresented(t *testing.T) {
|
||||||
e.Close()
|
e.Close()
|
||||||
t.Fatal("expecting TLS failure setting up server and client")
|
t.Fatal("expecting TLS failure setting up server and client")
|
||||||
}
|
}
|
||||||
if !strings.Contains(err.Error(), "bad certificate") {
|
// Check for either the old error (Go <=1.24) or the new one (Go 1.25+)
|
||||||
t.Fatalf("expecting TLS certificate error, got: %v", err)
|
// Go 1.24: "bad certificate"
|
||||||
|
// Go 1.25: "handshake failure"
|
||||||
|
errMsg := err.Error()
|
||||||
|
if !strings.Contains(errMsg, "bad certificate") && !strings.Contains(errMsg, "handshake failure") {
|
||||||
|
t.Fatalf("expecting a specific TLS certificate or handshake error, got: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue